From f6b2f6fb3cf1091199fef17c1115b19fc42a05c8 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Wed, 31 Jul 2024 13:29:54 +0200 Subject: [PATCH] Merge commit from fork * update samples * move away from publicKeyToBlockId * generate a full token in samples * move the public key list from 3rd party block requests * fix printing * move fact and rule translation to Authorizer.update_on_token * authorizer fixes * test workarounds * fix authorizer block translation * cleanup * v4.0.0 --- pom.xml | 2 +- .../biscuitsec/biscuit/token/Authorizer.java | 148 +++++++++--------- .../org/biscuitsec/biscuit/token/Biscuit.java | 31 ++-- .../org/biscuitsec/biscuit/token/Block.java | 54 ++++++- .../biscuit/token/ThirdPartyBlockRequest.java | 26 +-- .../biscuit/token/UnverifiedBiscuit.java | 43 +---- .../biscuit/token/builder/Biscuit.java | 11 ++ .../biscuit/token/builder/Block.java | 3 + .../token/format/SerializedBiscuit.java | 29 ++-- .../biscuitsec/biscuit/token/SamplesTest.java | 75 +++++---- .../biscuit/token/ThirdPartyTest.java | 4 +- src/test/resources/samples/README.md | 18 +-- src/test/resources/samples/samples.json | 24 ++- .../resources/samples/test024_third_party.bc | Bin 458 -> 458 bytes .../samples/test026_public_keys_interning.bc | Bin 1316 -> 1547 bytes 15 files changed, 237 insertions(+), 231 deletions(-) diff --git a/pom.xml b/pom.xml index 355fb830..2d52eb53 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.biscuitsec biscuit jar - 3.0.2 + 4.0.0 biscuit-java https://github.com/biscuit-auth/biscuit-java diff --git a/src/main/java/org/biscuitsec/biscuit/token/Authorizer.java b/src/main/java/org/biscuitsec/biscuit/token/Authorizer.java index f593a6df..b2d3c6f2 100644 --- a/src/main/java/org/biscuitsec/biscuit/token/Authorizer.java +++ b/src/main/java/org/biscuitsec/biscuit/token/Authorizer.java @@ -91,6 +91,29 @@ public Authorizer clone() { public void update_on_token() throws Error.FailedLogic { if (token != null) { + for(long i =0; i < token.blocks.size(); i++) { + Block block = token.blocks.get((int) i); + + if (block.externalKey.isDefined()) { + PublicKey pk = block.externalKey.get(); + long newKeyId = this.symbols.insert(pk); + if (!this.publicKeyToBlockId.containsKey(newKeyId)) { + List l = new ArrayList<>(); + l.add(i + 1); + this.publicKeyToBlockId.put(newKeyId, l); + } else { + this.publicKeyToBlockId.get(newKeyId).add(i + 1); + } + } + } + + TrustedOrigins authorityTrustedOrigins = TrustedOrigins.fromScopes( + token.authority.scopes, + TrustedOrigins.defaultOrigins(), + 0, + this.publicKeyToBlockId + ); + for (org.biscuitsec.biscuit.datalog.Fact fact : token.authority.facts) { org.biscuitsec.biscuit.datalog.Fact converted_fact = org.biscuitsec.biscuit.token.builder.Fact.convert_from(fact, token.symbols).convert(this.symbols); world.add_fact(new Origin(0), converted_fact); @@ -103,11 +126,51 @@ public void update_on_token() throws Error.FailedLogic { if(res.isLeft()){ throw new Error.FailedLogic(new LogicError.InvalidBlockRule(0, token.symbols.print_rule(converted_rule))); } + TrustedOrigins ruleTrustedOrigins = TrustedOrigins.fromScopes( + converted_rule.scopes(), + authorityTrustedOrigins, + 0, + this.publicKeyToBlockId + ); + world.add_rule((long) 0, ruleTrustedOrigins, converted_rule); } - this.publicKeyToBlockId.putAll(token.publicKeyToBlockId); - for(Long keyId: token.publicKeyToBlockId.keySet()) { - PublicKey pk = token.symbols.get_pk((int) keyId.longValue()).get(); - this.symbols.insert(pk); + + for(long i =0; i < token.blocks.size(); i++) { + Block block = token.blocks.get((int)i); + TrustedOrigins blockTrustedOrigins = TrustedOrigins.fromScopes( + block.scopes, + TrustedOrigins.defaultOrigins(), + i + 1, + this.publicKeyToBlockId + ); + + SymbolTable blockSymbols = token.symbols; + + if(block.externalKey.isDefined()) { + blockSymbols = new SymbolTable(block.symbols.symbols, block.publicKeys()); + } + + for (org.biscuitsec.biscuit.datalog.Fact fact : block.facts) { + org.biscuitsec.biscuit.datalog.Fact converted_fact = org.biscuitsec.biscuit.token.builder.Fact.convert_from(fact, blockSymbols).convert(this.symbols); + world.add_fact(new Origin(i + 1), converted_fact); + } + + for (org.biscuitsec.biscuit.datalog.Rule rule : block.rules) { + org.biscuitsec.biscuit.token.builder.Rule _rule = org.biscuitsec.biscuit.token.builder.Rule.convert_from(rule, blockSymbols); + org.biscuitsec.biscuit.datalog.Rule converted_rule = _rule.convert(this.symbols); + + Either res = _rule.validate_variables(); + if (res.isLeft()) { + throw new Error.FailedLogic(new LogicError.InvalidBlockRule(0, this.symbols.print_rule(converted_rule))); + } + TrustedOrigins ruleTrustedOrigins = TrustedOrigins.fromScopes( + converted_rule.scopes(), + blockTrustedOrigins, + i + 1, + this.publicKeyToBlockId + ); + world.add_rule((long) i + 1, ruleTrustedOrigins, converted_rule); + } } } } @@ -331,77 +394,8 @@ public Long authorize(RunLimits limits) throws Error { List errors = new LinkedList<>(); Option> policy_result = Option.none(); - Origin authorizerOrigin = Origin.authorizer(); TrustedOrigins authorizerTrustedOrigins = this.authorizerTrustedOrigins(); - if (token != null) { - for (org.biscuitsec.biscuit.datalog.Fact fact : token.authority.facts) { - org.biscuitsec.biscuit.datalog.Fact converted_fact = org.biscuitsec.biscuit.token.builder.Fact.convert_from(fact, token.symbols).convert(this.symbols); - world.add_fact(new Origin(0), converted_fact); - } - - TrustedOrigins authorityTrustedOrigins = TrustedOrigins.fromScopes( - token.authority.scopes, - TrustedOrigins.defaultOrigins(), - 0, - this.publicKeyToBlockId - ); - - for (org.biscuitsec.biscuit.datalog.Rule rule : token.authority.rules) { - org.biscuitsec.biscuit.token.builder.Rule _rule = org.biscuitsec.biscuit.token.builder.Rule.convert_from(rule, token.symbols); - org.biscuitsec.biscuit.datalog.Rule converted_rule = _rule.convert(this.symbols); - - Either res = _rule.validate_variables(); - if(res.isLeft()){ - throw new Error.FailedLogic(new LogicError.InvalidBlockRule(0, token.symbols.print_rule(converted_rule))); - } - TrustedOrigins ruleTrustedOrigins = TrustedOrigins.fromScopes( - converted_rule.scopes(), - authorityTrustedOrigins, - 0, - this.publicKeyToBlockId - ); - world.add_rule((long) 0, ruleTrustedOrigins, converted_rule); - } - - for (int i = 0; i < token.blocks.size(); i++) { - org.biscuitsec.biscuit.token.Block block = token.blocks.get(i); - TrustedOrigins blockTrustedOrigins = TrustedOrigins.fromScopes( - block.scopes, - TrustedOrigins.defaultOrigins(), - i + 1, - this.publicKeyToBlockId - ); - SymbolTable blockSymbols = token.symbols; - - if (block.externalKey.isDefined()) { - blockSymbols = new SymbolTable(block.symbols.symbols, token.symbols.publicKeys()); - } - - for (org.biscuitsec.biscuit.datalog.Fact fact : block.facts) { - org.biscuitsec.biscuit.datalog.Fact converted_fact = org.biscuitsec.biscuit.token.builder.Fact.convert_from(fact, blockSymbols).convert(this.symbols); - world.add_fact(new Origin(i + 1), converted_fact); - } - - for (org.biscuitsec.biscuit.datalog.Rule rule : block.rules) { - org.biscuitsec.biscuit.token.builder.Rule _rule = org.biscuitsec.biscuit.token.builder.Rule.convert_from(rule, blockSymbols); - org.biscuitsec.biscuit.datalog.Rule converted_rule = _rule.convert(this.symbols); - - Either res = _rule.validate_variables(); - if (res.isLeft()) { - throw new Error.FailedLogic(new LogicError.InvalidBlockRule(0, this.symbols.print_rule(converted_rule))); - } - TrustedOrigins ruleTrustedOrigins = TrustedOrigins.fromScopes( - converted_rule.scopes(), - blockTrustedOrigins, - i + 1, - this.publicKeyToBlockId - ); - world.add_rule((long) i + 1, ruleTrustedOrigins, converted_rule); - } - } - } - world.run(limits, symbols); for (int i = 0; i < this.checks.size(); i++) { @@ -529,7 +523,7 @@ public Long authorize(RunLimits limits) throws Error { ); SymbolTable blockSymbols = token.symbols; if(b.externalKey.isDefined()) { - blockSymbols = new SymbolTable(b.symbols.symbols, token.symbols.publicKeys()); + blockSymbols = new SymbolTable(b.symbols.symbols, b.publicKeys()); } for (int j = 0; j < b.checks.size(); j++) { @@ -608,7 +602,7 @@ public String print_world() { if (this.token != null) { for (int j = 0; j < this.token.authority.checks.size(); j++) { - checks.add("Block[0][" + j + "]: " + this.symbols.print_check(this.token.authority.checks.get(j))); + checks.add("Block[0][" + j + "]: " + token.symbols.print_check(this.token.authority.checks.get(j))); } for (int i = 0; i < this.token.blocks.size(); i++) { @@ -616,7 +610,7 @@ public String print_world() { SymbolTable blockSymbols = token.symbols; if(b.externalKey.isDefined()) { - blockSymbols = new SymbolTable(b.symbols.symbols, token.symbols.publicKeys()); + blockSymbols = new SymbolTable(b.symbols.symbols, b.publicKeys()); } for (int j = 0; j < b.checks.size(); j++) { @@ -662,7 +656,7 @@ public List>> checks() { List blockChecks = new ArrayList<>(); if(block.externalKey.isDefined()) { - SymbolTable blockSymbols = new SymbolTable(block.symbols.symbols, token.symbols.publicKeys()); + SymbolTable blockSymbols = new SymbolTable(block.symbols.symbols, block.publicKeys()); for(org.biscuitsec.biscuit.datalog.Check check: block.checks) { blockChecks.add(Check.convert_from(check, blockSymbols)); } diff --git a/src/main/java/org/biscuitsec/biscuit/token/Biscuit.java b/src/main/java/org/biscuitsec/biscuit/token/Biscuit.java index 662612b7..0d7a799d 100644 --- a/src/main/java/org/biscuitsec/biscuit/token/Biscuit.java +++ b/src/main/java/org/biscuitsec/biscuit/token/Biscuit.java @@ -7,7 +7,7 @@ import org.biscuitsec.biscuit.datalog.SymbolTable; import org.biscuitsec.biscuit.error.Error; import org.biscuitsec.biscuit.token.format.SerializedBiscuit; -import io.vavr.Tuple3; +import io.vavr.Tuple2; import io.vavr.control.Either; import io.vavr.control.Option; @@ -101,21 +101,20 @@ static private Biscuit make(final SecureRandom rng, final KeyPair root, final Op } else { SerializedBiscuit s = container.get(); List revocation_ids = s.revocation_identifiers(); - HashMap> publicKeyToBlockId = new HashMap<>(); Option c = Option.some(s); - return new Biscuit(authority, blocks, authority.symbols, s, publicKeyToBlockId, revocation_ids, root_key_id); + return new Biscuit(authority, blocks, authority.symbols, s, revocation_ids, root_key_id); } } Biscuit(Block authority, List blocks, SymbolTable symbols, SerializedBiscuit serializedBiscuit, - HashMap> publicKeyToBlockId, List revocation_ids) { - super(authority, blocks, symbols, serializedBiscuit, publicKeyToBlockId, revocation_ids); + List revocation_ids) { + super(authority, blocks, symbols, serializedBiscuit, revocation_ids); } Biscuit(Block authority, List blocks, SymbolTable symbols, SerializedBiscuit serializedBiscuit, - HashMap> publicKeyToBlockId, List revocation_ids, Option root_key_id) { - super(authority, blocks, symbols, serializedBiscuit, publicKeyToBlockId, revocation_ids, root_key_id); + List revocation_ids, Option root_key_id) { + super(authority, blocks, symbols, serializedBiscuit, revocation_ids, root_key_id); } /** @@ -248,14 +247,13 @@ static public Biscuit from_bytes_with_symbols(byte[] data, KeyDelegate delegate, * @return */ static Biscuit from_serialized_biscuit(SerializedBiscuit ser, SymbolTable symbols) throws Error { - Tuple3, HashMap>> t = ser.extractBlocks(symbols); + Tuple2> t = ser.extractBlocks(symbols); Block authority = t._1; ArrayList blocks = t._2; - HashMap> publicKeyToBlockId = t._3; List revocation_ids = ser.revocation_identifiers(); - return new Biscuit(authority, blocks, symbols, ser, publicKeyToBlockId, revocation_ids); + return new Biscuit(authority, blocks, symbols, ser, revocation_ids); } /** @@ -311,7 +309,7 @@ public Biscuit attenuate(org.biscuitsec.biscuit.token.builder.Block block) throw return attenuate(rng, keypair, block.build(builderSymbols)); } - public Biscuit attenuate(final SecureRandom rng, final KeyPair keypair,org.biscuitsec.biscuit.token.builder.Block block) throws Error { + public Biscuit attenuate(final SecureRandom rng, final KeyPair keypair, org.biscuitsec.biscuit.token.builder.Block block) throws Error { SymbolTable builderSymbols = new SymbolTable(this.symbols); return attenuate(rng, keypair, block.build(builderSymbols)); } @@ -354,10 +352,7 @@ public Biscuit attenuate(final SecureRandom rng, final KeyPair keypair, Block bl List revocation_ids = container.revocation_identifiers(); - HashMap> publicKeyToBlockId = new HashMap<>(); - publicKeyToBlockId.putAll(this.publicKeyToBlockId); - - return new Biscuit(copiedBiscuit.authority, blocks, symbols, container, publicKeyToBlockId, revocation_ids); + return new Biscuit(copiedBiscuit.authority, blocks, symbols, container, revocation_ids); } /** @@ -385,7 +380,11 @@ public String print() { s.append("\n\tblocks: [\n"); for (Block b : this.blocks) { s.append("\t\t"); - s.append(b.print(this.symbols)); + if(b.externalKey.isDefined()) { + s.append(b.print(b.symbols)); + } else { + s.append(b.print(this.symbols)); + } s.append("\n"); } s.append("\t]\n}"); diff --git a/src/main/java/org/biscuitsec/biscuit/token/Block.java b/src/main/java/org/biscuitsec/biscuit/token/Block.java index 975a006a..1852271d 100644 --- a/src/main/java/org/biscuitsec/biscuit/token/Block.java +++ b/src/main/java/org/biscuitsec/biscuit/token/Block.java @@ -102,10 +102,10 @@ public String print(SymbolTable symbol_table) { s.append("Block"); s.append(" {\n\t\tsymbols: "); s.append(this.symbols.symbols); - s.append("\n\t\tpublic keys: "); - s.append(this.publicKeys); s.append("\n\t\tsymbol public keys: "); s.append(this.symbols.publicKeys()); + s.append("\n\t\tblock public keys: "); + s.append(this.publicKeys); s.append("\n\t\tcontext: "); s.append(this.context); if(this.externalKey.isDefined()) { @@ -137,6 +137,47 @@ public String print(SymbolTable symbol_table) { return s.toString(); } + public String printCode(SymbolTable symbol_table) { + StringBuilder s = new StringBuilder(); + + SymbolTable local_symbols; + if(this.externalKey.isDefined()) { + local_symbols = new SymbolTable(this.symbols); + for(PublicKey pk: symbol_table.publicKeys()) { + local_symbols.insert(pk); + } + } else { + local_symbols = symbol_table; + } + /*s.append("Block"); + s.append(" {\n\t\tsymbols: "); + s.append(this.symbols.symbols); + s.append("\n\t\tsymbol public keys: "); + s.append(this.symbols.publicKeys()); + s.append("\n\t\tblock public keys: "); + s.append(this.publicKeys); + s.append("\n\t\tcontext: "); + s.append(this.context); + if(this.externalKey.isDefined()) { + s.append("\n\t\texternal key: "); + s.append(this.externalKey.get().toString()); + }*/ + for (Scope scope : this.scopes) { + s.append("trusting "+local_symbols.print_scope(scope)+"\n"); + } + for (Fact f : this.facts) { + s.append(local_symbols.print_fact(f)+";\n"); + } + for (Rule r : this.rules) { + s.append(local_symbols.print_rule(r)+";\n"); + } + for (Check c : this.checks) { + s.append(local_symbols.print_check(c)+";\n"); + } + + return s.toString(); + } + /** * Serializes a Block to its Protobuf representation * @@ -199,8 +240,11 @@ int getSchemaVersion() { } } - if(containsScopes || containsCheckAll || containsV4 || this.externalKey.isDefined()) { + if(this.externalKey.isDefined()) { return SerializedBiscuit.MAX_SCHEMA_VERSION; + + }else if(containsScopes || containsCheckAll || containsV4) { + return 4; } else { return SerializedBiscuit.MIN_SCHEMA_VERSION; } @@ -286,7 +330,9 @@ static public Either deserialize(Schema.Block b, Optio ArrayList publicKeys = new ArrayList<>(); for (Schema.PublicKey pk: b.getPublicKeysList()) { try { - publicKeys.add(PublicKey.deserialize(pk)); + PublicKey key =PublicKey.deserialize(pk); + publicKeys.add(key); + symbols.publicKeys().add(key); } catch(Error.FormatError e) { return Left(e); } diff --git a/src/main/java/org/biscuitsec/biscuit/token/ThirdPartyBlockRequest.java b/src/main/java/org/biscuitsec/biscuit/token/ThirdPartyBlockRequest.java index 50b1298d..cce32e5f 100644 --- a/src/main/java/org/biscuitsec/biscuit/token/ThirdPartyBlockRequest.java +++ b/src/main/java/org/biscuitsec/biscuit/token/ThirdPartyBlockRequest.java @@ -23,19 +23,13 @@ public class ThirdPartyBlockRequest { PublicKey previousKey; - List publicKeys; - ThirdPartyBlockRequest(PublicKey previousKey, List publicKeys) { + ThirdPartyBlockRequest(PublicKey previousKey) { this.previousKey = previousKey; - this.publicKeys = publicKeys; } public Either createBlock(KeyPair keyPair, Block blockBuilder) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { SymbolTable symbols = new SymbolTable(); - for(PublicKey pk: this.publicKeys) { - symbols.insert(pk); - } - org.biscuitsec.biscuit.token.Block block = blockBuilder.build(symbols, Option.some(keyPair.public_key())); Either res = block.to_bytes(); @@ -66,20 +60,12 @@ public Schema.ThirdPartyBlockRequest serialize() throws Error.FormatError.Serial Schema.ThirdPartyBlockRequest.Builder b = Schema.ThirdPartyBlockRequest.newBuilder(); b.setPreviousKey(this.previousKey.serialize()); - for(PublicKey pk: this.publicKeys) { - b.addPublicKeys(pk.serialize()); - } - return b.build(); } static public ThirdPartyBlockRequest deserialize(Schema.ThirdPartyBlockRequest b) throws Error.FormatError.DeserializationError { PublicKey previousKey = PublicKey.deserialize(b.getPreviousKey()); - List publicKeys = new ArrayList<>(); - for(Schema.PublicKey pk: b.getPublicKeysList()) { - publicKeys.add(PublicKey.deserialize(pk)); - } - return new ThirdPartyBlockRequest(previousKey, publicKeys); + return new ThirdPartyBlockRequest(previousKey); } static public ThirdPartyBlockRequest fromBytes(byte[] slice) throws InvalidProtocolBufferException, Error.FormatError.DeserializationError { @@ -100,22 +86,18 @@ public boolean equals(Object o) { ThirdPartyBlockRequest that = (ThirdPartyBlockRequest) o; - if (!Objects.equals(previousKey, that.previousKey)) return false; - return Objects.equals(publicKeys, that.publicKeys); + return Objects.equals(previousKey, that.previousKey); } @Override public int hashCode() { - int result = previousKey != null ? previousKey.hashCode() : 0; - result = 31 * result + (publicKeys != null ? publicKeys.hashCode() : 0); - return result; + return previousKey != null ? previousKey.hashCode() : 0; } @Override public String toString() { return "ThirdPartyBlockRequest{" + "previousKey=" + previousKey + - ", publicKeys=" + publicKeys + '}'; } } diff --git a/src/main/java/org/biscuitsec/biscuit/token/UnverifiedBiscuit.java b/src/main/java/org/biscuitsec/biscuit/token/UnverifiedBiscuit.java index 07ac2e9a..3f620a84 100644 --- a/src/main/java/org/biscuitsec/biscuit/token/UnverifiedBiscuit.java +++ b/src/main/java/org/biscuitsec/biscuit/token/UnverifiedBiscuit.java @@ -1,14 +1,13 @@ package org.biscuitsec.biscuit.token; import biscuit.format.schema.Schema; -import net.i2p.crypto.eddsa.EdDSAEngine; import org.biscuitsec.biscuit.crypto.KeyDelegate; import org.biscuitsec.biscuit.crypto.KeyPair; import org.biscuitsec.biscuit.crypto.PublicKey; import org.biscuitsec.biscuit.error.Error; import org.biscuitsec.biscuit.token.format.ExternalSignature; import org.biscuitsec.biscuit.token.format.SerializedBiscuit; -import io.vavr.Tuple3; +import io.vavr.Tuple2; import io.vavr.control.Either; import io.vavr.control.Option; import org.biscuitsec.biscuit.datalog.Check; @@ -30,27 +29,24 @@ public class UnverifiedBiscuit { final SerializedBiscuit serializedBiscuit; final List revocation_ids; final Option root_key_id; - final HashMap> publicKeyToBlockId; UnverifiedBiscuit(Block authority, List blocks, SymbolTable symbols, SerializedBiscuit serializedBiscuit, - HashMap> publicKeyToBlockId, List revocation_ids) { + List revocation_ids) { this.authority = authority; this.blocks = blocks; this.symbols = symbols; this.serializedBiscuit = serializedBiscuit; - this.publicKeyToBlockId = publicKeyToBlockId; this.revocation_ids = revocation_ids; this.root_key_id = Option.none(); } UnverifiedBiscuit(Block authority, List blocks, SymbolTable symbols, SerializedBiscuit serializedBiscuit, - HashMap> publicKeyToBlockId, List revocation_ids, + List revocation_ids, Option root_key_id) { this.authority = authority; this.blocks = blocks; this.symbols = symbols; this.serializedBiscuit = serializedBiscuit; - this.publicKeyToBlockId = publicKeyToBlockId; this.revocation_ids = revocation_ids; this.root_key_id = root_key_id; } @@ -96,14 +92,13 @@ static public UnverifiedBiscuit from_bytes_with_symbols(byte[] data, SymbolTable * @return UnverifiedBiscuit */ static private UnverifiedBiscuit from_serialized_biscuit(SerializedBiscuit ser, SymbolTable symbols) throws Error { - Tuple3, HashMap>> t = ser.extractBlocks(symbols); + Tuple2> t = ser.extractBlocks(symbols); Block authority = t._1; ArrayList blocks = t._2; - HashMap> publicKeyToBlockId = t._3; List revocation_ids = ser.revocation_identifiers(); - return new UnverifiedBiscuit(authority, blocks, symbols, ser, publicKeyToBlockId, revocation_ids); + return new UnverifiedBiscuit(authority, blocks, symbols, ser, revocation_ids); } /** @@ -186,11 +181,7 @@ public UnverifiedBiscuit attenuate(final SecureRandom rng, final KeyPair keypair List revocation_ids = container.revocation_identifiers(); - HashMap> publicKeyToBlockId = new HashMap<>(); - publicKeyToBlockId.putAll(this.publicKeyToBlockId); - - return new UnverifiedBiscuit(copiedBiscuit.authority, blocks, symbols, container, - publicKeyToBlockId, revocation_ids); + return new UnverifiedBiscuit(copiedBiscuit.authority, blocks, symbols, container, revocation_ids); } //FIXME: attenuate 3rd Party @@ -245,8 +236,7 @@ public ThirdPartyBlockRequest thirdPartyRequest() { previousKey = this.serializedBiscuit.blocks.get(this.serializedBiscuit.blocks.size() - 1).key; } - List publicKeys = new ArrayList<>(this.symbols.publicKeys()); - return new ThirdPartyBlockRequest(previousKey, publicKeys); + return new ThirdPartyBlockRequest(previousKey); } @@ -303,25 +293,8 @@ public UnverifiedBiscuit appendThirdPartyBlock(PublicKey externalKey, ThirdParty } blocks.add(block); - for(PublicKey pk: block.publicKeys) { - symbols.insert(pk); - } - - long pkIndex = symbols.insert(externalKey); - - HashMap> publicKeyToBlockId = new HashMap<>(); - publicKeyToBlockId.putAll(this.publicKeyToBlockId); - if(publicKeyToBlockId.containsKey(pkIndex)) { - publicKeyToBlockId.get(pkIndex).add((long)this.blocks.size()+1); - } else { - List list = new ArrayList<>(); - list.add((long)this.blocks.size()+1); - publicKeyToBlockId.put(pkIndex, list); - } - List revocation_ids = container.revocation_identifiers(); - - return new UnverifiedBiscuit(copiedBiscuit.authority, blocks, symbols, container, publicKeyToBlockId, revocation_ids); + return new UnverifiedBiscuit(copiedBiscuit.authority, blocks, symbols, container, revocation_ids); } /** diff --git a/src/main/java/org/biscuitsec/biscuit/token/builder/Biscuit.java b/src/main/java/org/biscuitsec/biscuit/token/builder/Biscuit.java index db21a76b..66c202d2 100644 --- a/src/main/java/org/biscuitsec/biscuit/token/builder/Biscuit.java +++ b/src/main/java/org/biscuitsec/biscuit/token/builder/Biscuit.java @@ -50,6 +50,17 @@ public Biscuit(final SecureRandom rng, final KeyPair root, Option root_ this.root_key_id = root_key_id; } + public Biscuit(final SecureRandom rng, final KeyPair root, Option root_key_id, org.biscuitsec.biscuit.token.builder.Block block) { + this.rng = rng; + this.root = root; + this.root_key_id = root_key_id; + this.context = block.context; + this.facts = block.facts; + this.rules = block.rules; + this.checks = block.checks; + this.scopes = block.scopes; + } + public Biscuit add_authority_fact(org.biscuitsec.biscuit.token.builder.Fact f) throws Error.Language { f.validate(); this.facts.add(f); diff --git a/src/main/java/org/biscuitsec/biscuit/token/builder/Block.java b/src/main/java/org/biscuitsec/biscuit/token/builder/Block.java index 972a694c..344f51c9 100644 --- a/src/main/java/org/biscuitsec/biscuit/token/builder/Block.java +++ b/src/main/java/org/biscuitsec/biscuit/token/builder/Block.java @@ -109,6 +109,9 @@ public org.biscuitsec.biscuit.token.Block build(SymbolTable symbols) { } public org.biscuitsec.biscuit.token.Block build(SymbolTable symbols, final Option externalKey) { + if(externalKey.isDefined()) { + symbols = new SymbolTable(); + } int symbol_start = symbols.currentOffset(); int publicKeyStart = symbols.currentPublicKeyOffset(); diff --git a/src/main/java/org/biscuitsec/biscuit/token/format/SerializedBiscuit.java b/src/main/java/org/biscuitsec/biscuit/token/format/SerializedBiscuit.java index 9f9609c1..c6a31f08 100644 --- a/src/main/java/org/biscuitsec/biscuit/token/format/SerializedBiscuit.java +++ b/src/main/java/org/biscuitsec/biscuit/token/format/SerializedBiscuit.java @@ -1,6 +1,7 @@ package org.biscuitsec.biscuit.token.format; import biscuit.format.schema.Schema; +import io.vavr.Tuple2; import org.biscuitsec.biscuit.crypto.KeyDelegate; import org.biscuitsec.biscuit.crypto.KeyPair; import org.biscuitsec.biscuit.crypto.PublicKey; @@ -34,7 +35,7 @@ public class SerializedBiscuit { public Option root_key_id; public static int MIN_SCHEMA_VERSION = 3; - public static int MAX_SCHEMA_VERSION = 4; + public static int MAX_SCHEMA_VERSION = 5; /** * Deserializes a SerializedBiscuit from a byte array @@ -86,7 +87,6 @@ static SerializedBiscuit from_bytes_inner(Schema.Biscuit data, org.biscuitsec.bi Either res = b.verify(root); if (res.isLeft()) { - //System.out.println("verification error: "+e.toString()); throw res.getLeft(); } else { return b; @@ -409,7 +409,6 @@ static Either verifyBlockSignatu sgr2.update(block); sgr2.update(algo_buf2); sgr2.update(publicKey.toBytes()); - Either authRes = Block.from_bytes(block, Option.none()); if (!sgr2.verify(signedBlock.externalSignature.get().signature)) { return Left(new Error.FormatError.Signature.InvalidSignature("external signature error: Verification equation was not satisfied")); @@ -419,7 +418,7 @@ static Either verifyBlockSignatu return Right(next_key); } - public Tuple3, HashMap>> extractBlocks(SymbolTable symbols) throws Error { + public Tuple2> extractBlocks(SymbolTable symbols) throws Error { ArrayList> blockExternalKeys = new ArrayList<>(); Either authRes = Block.from_bytes(this.authority.block, Option.none()); if (authRes.isLeft()) { @@ -449,32 +448,22 @@ public Tuple3, HashMap>> extractBlocks( // blocks with external signatures keep their own symbol table if(bdata.externalSignature.isDefined()) { - symbols.insert(bdata.externalSignature.get().key); + //symbols.insert(bdata.externalSignature.get().key); blockExternalKeys.add(Option.some(bdata.externalSignature.get().key)); } else { blockExternalKeys.add(Option.none()); for (String s : block.symbols().symbols) { symbols.add(s); } + for(org.biscuitsec.biscuit.crypto.PublicKey pk: block.publicKeys()) { + symbols.insert(pk); + } } - for(org.biscuitsec.biscuit.crypto.PublicKey pk: block.publicKeys()) { - symbols.insert(pk); - } + blocks.add(block); } - HashMap> publicKeyToBlockId = new HashMap<>(); - for(int blockIndex = 0; blockIndex < blockExternalKeys.size(); blockIndex++) { - if(blockExternalKeys.get(blockIndex).isDefined()) { - PublicKey pk = blockExternalKeys.get(blockIndex).get(); - long keyIndex = symbols.insert(pk); - if(!publicKeyToBlockId.containsKey(keyIndex)) { - publicKeyToBlockId.put(keyIndex, new ArrayList<>()); - } - publicKeyToBlockId.get(keyIndex).add((long) blockIndex); - } - } - return new Tuple3<>(authority, blocks, publicKeyToBlockId); + return new Tuple2<>(authority, blocks); } public Either seal() throws InvalidKeyException, NoSuchAlgorithmException, SignatureException { diff --git a/src/test/java/org/biscuitsec/biscuit/token/SamplesTest.java b/src/test/java/org/biscuitsec/biscuit/token/SamplesTest.java index a7dffc71..29bd5c16 100644 --- a/src/test/java/org/biscuitsec/biscuit/token/SamplesTest.java +++ b/src/test/java/org/biscuitsec/biscuit/token/SamplesTest.java @@ -26,6 +26,7 @@ import java.io.BufferedInputStream; import java.io.InputStream; import java.io.InputStreamReader; +import java.security.SecureRandom; import java.time.Duration; import java.util.*; import java.util.stream.Collectors; @@ -48,21 +49,19 @@ Stream jsonTest() { return sample.testcases.stream().map(t -> process_testcase(t, publicKey, keyPair)); } - void compareBlocks(List sampleBlocks, List blocks) { - assertEquals(sampleBlocks.size(), blocks.size()); - List> comparisonList = IntStream.range(0, sampleBlocks.size()) - .mapToObj(i -> new Tuple2<>(sampleBlocks.get(i), blocks.get(i))) - .collect(Collectors.toList()); + void compareBlocks(KeyPair root, List sampleBlocks, Biscuit token) throws Error { + assertEquals(sampleBlocks.size(), 1+token.blocks.size()); + Option sampleToken = Option.none(); + Biscuit b = compareBlock(root, sampleToken, 0, sampleBlocks.get(0), token.authority, token.symbols); + sampleToken = Option.some(b); - // for each token we start from the base symbol table - SymbolTable baseSymbols = new SymbolTable(); - - io.vavr.collection.Stream.ofAll(comparisonList).zipWithIndex().forEach(indexedItem -> { - compareBlock(baseSymbols, indexedItem._2, indexedItem._1._1, indexedItem._1._2); - }); + for(int i=0; i < token.blocks.size(); i++) { + b = compareBlock(root, sampleToken, i+1, sampleBlocks.get(i+1), token.blocks.get(i), token.symbols); + sampleToken = Option.some(b); + } } - void compareBlock(SymbolTable baseSymbols, long sampleBlockIndex, Block sampleBlock, org.biscuitsec.biscuit.token.Block block) { + Biscuit compareBlock(KeyPair root, Option sampleToken, long sampleBlockIndex, Block sampleBlock, org.biscuitsec.biscuit.token.Block tokenBlock, SymbolTable tokenSymbols) throws Error { Option sampleExternalKey = sampleBlock.getExternalKey(); List samplePublicKeys = sampleBlock.getPublicKeys(); String sampleDatalog = sampleBlock.getCode().replace("\"","\\\""); @@ -71,40 +70,40 @@ void compareBlock(SymbolTable baseSymbols, long sampleBlockIndex, Block sampleBl // the invalid block rule with unbound variable cannot be parsed if(outputSample.isLeft()) { - return; + return sampleToken.get(); } - SymbolTable sampleSymbols; - if (!block.externalKey.isDefined()) { - sampleSymbols = new SymbolTable(baseSymbols); + Biscuit newSampleToken; + if(!sampleToken.isDefined()) { + org.biscuitsec.biscuit.token.builder.Biscuit builder = new org.biscuitsec.biscuit.token.builder.Biscuit(new SecureRandom(), root, Option.none(), outputSample.get()); + newSampleToken = builder.build(); } else { - sampleSymbols = new SymbolTable(); - - for(PublicKey pk: baseSymbols.publicKeys()) { - sampleSymbols.insert(pk); - } + Biscuit s = sampleToken.get(); + newSampleToken = s.attenuate(outputSample.get()); } - org.biscuitsec.biscuit.token.Block generatedSampleBlock = outputSample.get().build(sampleSymbols); - - if(!block.externalKey.isDefined()) { - generatedSampleBlock.symbols.symbols.forEach(baseSymbols::add); + org.biscuitsec.biscuit.token.Block generatedSampleBlock; + if(!sampleToken.isDefined()) { + generatedSampleBlock = newSampleToken.authority; } else { - generatedSampleBlock.setExternalKey(block.externalKey.get()); - generatedSampleBlock.version = SerializedBiscuit.MAX_SCHEMA_VERSION; - baseSymbols.insert(block.externalKey.get()); + generatedSampleBlock = newSampleToken.blocks.get((int)sampleBlockIndex-1); } - for(PublicKey pk: generatedSampleBlock.publicKeys) { - baseSymbols.insert(pk); - } - System.out.println(baseSymbols.symbols); + System.out.println("generated block: "); + System.out.println(generatedSampleBlock.print(newSampleToken.symbols)); + System.out.println("deserialized block: "); + System.out.println(tokenBlock.print(newSampleToken.symbols)); + + SymbolTable tokenBlockSymbols = tokenSymbols; + SymbolTable generatedBlockSymbols = newSampleToken.symbols; + assertEquals(generatedSampleBlock.printCode(generatedBlockSymbols), tokenBlock.printCode(tokenBlockSymbols)); + + /* FIXME: to generate the same sample block, we need the samples to provide the external private key + assertEquals(generatedSampleBlock, tokenBlock); + assertArrayEquals(generatedSampleBlock.to_bytes().get(), tokenBlock.to_bytes().get()); + */ - System.out.println(generatedSampleBlock.print(baseSymbols)); - System.out.println(block.print(baseSymbols)); - assertEquals(generatedSampleBlock.print(baseSymbols), block.print(baseSymbols)); - assertEquals(generatedSampleBlock, block); - assertArrayEquals(generatedSampleBlock.to_bytes().get(), block.to_bytes().get()); + return newSampleToken; } DynamicTest process_testcase(final TestCase testCase, final PublicKey publicKey, final KeyPair privateKey) { @@ -129,7 +128,7 @@ DynamicTest process_testcase(final TestCase testCase, final PublicKey publicKey, allBlocks.add(token.authority); allBlocks.addAll(token.blocks); - compareBlocks(testCase.token, allBlocks); + compareBlocks(privateKey, testCase.token, token); byte[] ser_block_authority = token.authority.to_bytes().get(); System.out.println(Arrays.toString(ser_block_authority)); diff --git a/src/test/java/org/biscuitsec/biscuit/token/ThirdPartyTest.java b/src/test/java/org/biscuitsec/biscuit/token/ThirdPartyTest.java index aca09add..4d9e9e49 100644 --- a/src/test/java/org/biscuitsec/biscuit/token/ThirdPartyTest.java +++ b/src/test/java/org/biscuitsec/biscuit/token/ThirdPartyTest.java @@ -81,8 +81,10 @@ public void testRoundTrip() throws NoSuchAlgorithmException, SignatureException, @Test public void testPublicKeyInterning() throws NoSuchAlgorithmException, SignatureException, InvalidKeyException, CloneNotSupportedException, Error { + // this makes a deterministic RNG + SecureRandom rng = SecureRandom.getInstance("SHA1PRNG"); byte[] seed = {0, 0, 0, 0}; - SecureRandom rng = new SecureRandom(seed); + rng.setSeed(seed); System.out.println("preparing the authority block"); diff --git a/src/test/resources/samples/README.md b/src/test/resources/samples/README.md index 0e61691a..e5fbafe3 100644 --- a/src/test/resources/samples/README.md +++ b/src/test/resources/samples/README.md @@ -1841,7 +1841,7 @@ allow if true; revocation ids: - `470e4bf7aa2a01ab39c98150bd06aa15b4aa5d86509044a8809a8634cd8cf2b42269a51a774b65d10bac9369d013070b00187925196a8e680108473f11cf8f03` -- `93a7315ab1272da9eeef015f6fecbc9ac96fe4660e6204bf64ea2105ebe309e9c9cadc0a26c5604f13910fae3f2cd0800756afb6b6b208bf77adeb1ab2f42405` +- `342167bc54bc642b6718a276875e55b6d39e9b21e4ce13b926a3d398b6c057fc436385bf4c817a16f9ecdf0b0d950e8b8258a20aeb3fd8896c5e9c1f0a53da03` authorizer world: ``` @@ -2041,7 +2041,7 @@ check if true trusting previous, ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755 1: symbols: [] -public keys: ["ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463"] +public keys: ["ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189"] external signature by: "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189" @@ -2055,7 +2055,7 @@ check if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5 2: symbols: [] -public keys: [] +public keys: ["ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189"] external signature by: "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463" @@ -2068,7 +2068,7 @@ check if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5 3: symbols: [] -public keys: [] +public keys: ["ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189"] external signature by: "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463" @@ -2081,7 +2081,7 @@ check if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5 4: symbols: [] -public keys: ["ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136"] +public keys: ["ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136"] ``` query(4); @@ -2103,10 +2103,10 @@ allow if true; revocation ids: - `3771cefe71beb21ead35a59c8116ee82627a5717c0295f35980662abccb159fe1b37848cb1818e548656bd4fd882d0094a2daab631c76b2b72e3a093914bfe04` -- `45133b90f228a81fe4d3042a79f6c6b7608e656e903d6b1f4db32cd774b09b8315af360879a5f210ad7be37ff55e3eb34f237bcc9711407b6329ac6018bfb400` -- `179f054f3c572646aba5013159ae192ac42f5666dbdd984129955f4652b6829e59f54aa251e451f96329d42a2524ce569c3e1ec52e708b642dd8994af51dd703` -- `edab54789d6656936fcd28200b9c61643434842d531f09f209fad555e11ff53174db174dafba126e6de448983a56f78d2042bc5782d71a45799c022fe69fb30d` -- `6a62306831e9dbe83e7b33db96b758c77dd690930f2d2d87e239b210b1944c5582bf6d7e1bfea8e7f928c27f2fff0e2ee2e0adc41e11e0c3abe8d7b96b9ede07` +- `6528db2c9a561ada9086268549a600a8a52ff434ea8183812623eec0e9b6c5d3c41ab7868808623021d92294d583afdf92f4354bcdaa1bc50453e1b89afd630d` +- `5d5679fe69bfe74b7919323515e9ecba9d01422b16be9341b57f88e695b2bb0bd7966b781001d2b9e00ee618fdc239c96e17e32cb379f13f12d6bd7b1b47ad04` +- `c37bf24c063f0310eccab8864e48dbeffcdd7240b4f8d1e01eba4fc703e6c9082b845bb55543b10f008dc7f4e78540411912ac1f36fa2aa90011dca40f323b09` +- `3f675d6c364e06405d4868c904e40f3d81c32b083d91586db814d4cb4bf536b4ba209d82f11b4cb6da293b60b20d6122fc3e0e08e80c381dee83edd848211900` authorizer world: ``` diff --git a/src/test/resources/samples/samples.json b/src/test/resources/samples/samples.json index acae28a8..d97790a7 100644 --- a/src/test/resources/samples/samples.json +++ b/src/test/resources/samples/samples.json @@ -1798,7 +1798,7 @@ "authorizer_code": "allow if true;\n", "revocation_ids": [ "470e4bf7aa2a01ab39c98150bd06aa15b4aa5d86509044a8809a8634cd8cf2b42269a51a774b65d10bac9369d013070b00187925196a8e680108473f11cf8f03", - "93a7315ab1272da9eeef015f6fecbc9ac96fe4660e6204bf64ea2105ebe309e9c9cadc0a26c5604f13910fae3f2cd0800756afb6b6b208bf77adeb1ab2f42405" + "342167bc54bc642b6718a276875e55b6d39e9b21e4ce13b926a3d398b6c057fc436385bf4c817a16f9ecdf0b0d950e8b8258a20aeb3fd8896c5e9c1f0a53da03" ] } } @@ -1939,26 +1939,34 @@ { "symbols": [], "public_keys": [ - "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463" + "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", + "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189" ], "external_key": "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189", "code": "query(1);\nquery(1, 2) <- query(1), query(2) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n" }, { "symbols": [], - "public_keys": [], + "public_keys": [ + "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", + "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189" + ], "external_key": "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "code": "query(2);\ncheck if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n" }, { "symbols": [], - "public_keys": [], + "public_keys": [ + "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", + "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189" + ], "external_key": "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "code": "query(3);\ncheck if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n" }, { "symbols": [], "public_keys": [ + "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136" ], "external_key": null, @@ -2082,10 +2090,10 @@ "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", - "45133b90f228a81fe4d3042a79f6c6b7608e656e903d6b1f4db32cd774b09b8315af360879a5f210ad7be37ff55e3eb34f237bcc9711407b6329ac6018bfb400", - "179f054f3c572646aba5013159ae192ac42f5666dbdd984129955f4652b6829e59f54aa251e451f96329d42a2524ce569c3e1ec52e708b642dd8994af51dd703", - "edab54789d6656936fcd28200b9c61643434842d531f09f209fad555e11ff53174db174dafba126e6de448983a56f78d2042bc5782d71a45799c022fe69fb30d", - "6a62306831e9dbe83e7b33db96b758c77dd690930f2d2d87e239b210b1944c5582bf6d7e1bfea8e7f928c27f2fff0e2ee2e0adc41e11e0c3abe8d7b96b9ede07" + "6528db2c9a561ada9086268549a600a8a52ff434ea8183812623eec0e9b6c5d3c41ab7868808623021d92294d583afdf92f4354bcdaa1bc50453e1b89afd630d", + "5d5679fe69bfe74b7919323515e9ecba9d01422b16be9341b57f88e695b2bb0bd7966b781001d2b9e00ee618fdc239c96e17e32cb379f13f12d6bd7b1b47ad04", + "c37bf24c063f0310eccab8864e48dbeffcdd7240b4f8d1e01eba4fc703e6c9082b845bb55543b10f008dc7f4e78540411912ac1f36fa2aa90011dca40f323b09", + "3f675d6c364e06405d4868c904e40f3d81c32b083d91586db814d4cb4bf536b4ba209d82f11b4cb6da293b60b20d6122fc3e0e08e80c381dee83edd848211900" ] } } diff --git a/src/test/resources/samples/test024_third_party.bc b/src/test/resources/samples/test024_third_party.bc index 7bca415c6f4aeff3f27628adbaa6211f6e263493..d2aef52815e08c1d47cfaaec9ad0b8eaa1bc13e4 100644 GIT binary patch delta 149 zcmV;G0BZlr1Ih!Cxd8={xziGHPFJ%uTceGU^8b6lYjwA DDLF|c delta 149 zcmV;G0BZlr1Ih!Cxd8-`xLCT|;|b}> z%G?Sj#b8epkq@pvEYN@lR@=B?SrtgW zV^p2!&o#v7y*c4|mM^o6M_}!R0WSsp4EnTt{TxTWP@!Q)c>ZFTKI$ z8n(0|HCj$n>(PnFTYn$(eskd3wC?9C`-3g2zTN!0+_K<;QLR;6FRO^E-&dZ=ZyD9u z?=o?90DUl7ib<6y*GDla)yIZa{>$9|+`CfJ$W-*@n_Y7mowUXFO?KQ`-|=kfrrq4v zr)5_NFkagEfbW^a-$Rxs^TZ$PY_9xhFLZ5hwY2+M7LevNg^q|dI*wSk9{@1e4uW`9LOEWUq&z0OaNh!U&xp~*jxgR%7;$Shkx2+&oW>*eJEYL2uEZV%?HJ;TmrpS(M60sXpR+HJ76($$4_&M08$L5&%u{p$gWSnGq!f)GnSewIkVnpr^kt?UYznX2? or7*YYqqNVqTbkAhn|KqI{@C$xyx_5reb@Zrnb^rhX delta 627 zcmeC?S;9482m4JXt`!i(pVw?y=j>@H<1lCqRuKyZm zx7lC0`pk4ehw5a_H3<^?w=gJWa5>~GogeS{`oZscj-T88wbcqbJDWVEK2Da(nfB?( z!Um0>$7J+w+<2ZQt?+*?H`|J6TiHL4ANH&Z-L}(0k4@$>V-$M6HWDn8 z9hp>dxcNAfM!ooaR)3ptHMiAE84V-XNopO@4@->rId*bK^$NOEbZ^Y``YL;!8RXtO+4Z{HS(@K`tV(tIo%CEFT;`tNLCeRj z_9{`%VQXUZ7(WJT@A~xPi}hiV&)e7k+{dz&(eG~m+%H>BXR)VJaPUHA zTn<)e(WrmBI;3K5TG-_Lvlk<Yvmj!{b%zx^MV}AuXE_}v-rPzZbvU_)Vo-caIWN|(ROF64_;!C z4~jSceCyWN)xYe4_sJQj)zSr59cr7QzyGw8+V5>Mf=k#I)OyyifgQ{$b%c>CYVv;; ztI6@K9u8Sa1{sDgZ@;jsHoiS=d&KeDYZE5(>*}^YvfL!Faf(l9)BfB#>3=Jp|I|2C fum7J<@6m&`N8|(_9A5q6`p)cm_t+;tXH@|Jec${W