diff --git a/src/main/java/org/eclipse/biscuit/crypto/BlockSignatureBuffer.java b/src/main/java/org/eclipse/biscuit/crypto/BlockSignatureBuffer.java index ef0ed869..29dd02ba 100644 --- a/src/main/java/org/eclipse/biscuit/crypto/BlockSignatureBuffer.java +++ b/src/main/java/org/eclipse/biscuit/crypto/BlockSignatureBuffer.java @@ -5,48 +5,192 @@ package org.eclipse.biscuit.crypto; +import static io.vavr.API.Left; +import static io.vavr.API.Right; + +import biscuit.format.schema.Schema; +import io.vavr.control.Either; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; import java.util.Optional; +import java.util.stream.Stream; +import org.eclipse.biscuit.error.Error; import org.eclipse.biscuit.token.format.ExternalSignature; +import org.eclipse.biscuit.token.format.SerializedBiscuit; +import org.eclipse.biscuit.token.format.SignedBlock; public final class BlockSignatureBuffer { - public static final int HEADER_SIZE = 4; + public static final int THIRD_PARTY_SIGNATURE_VERSION = 1; + public static final int DATALOG_3_3_SIGNATURE_VERSION = 1; + public static final int NON_ED25519_SIGNATURE_VERSION = 1; + + private static final byte[] BLOCK_VERSION = + "\0BLOCK\0\0VERSION\0".getBytes(StandardCharsets.US_ASCII); + private static final byte[] EXTERNAL_VERSION = + "\0EXTERNAL\0\0VERSION\0".getBytes(StandardCharsets.US_ASCII); + private static final byte[] PAYLOAD = "\0PAYLOAD\0".getBytes(StandardCharsets.US_ASCII); + private static final byte[] ALGORITHM = "\0ALGORITHM\0".getBytes(StandardCharsets.US_ASCII); + private static final byte[] NEXTKEY = "\0NEXTKEY\0".getBytes(StandardCharsets.US_ASCII); + private static final byte[] PREVSIG = "\0PREVSIG\0".getBytes(StandardCharsets.US_ASCII); + private static final byte[] EXTERNALSIG = "\0EXTERNALSIG\0".getBytes(StandardCharsets.US_ASCII); private BlockSignatureBuffer() {} - public static byte[] getBufferSignature(PublicKey nextPubKey, byte[] data) { - return getBufferSignature(nextPubKey, data, Optional.empty()); - } - - public static byte[] getBufferSignature( - PublicKey nextPubKey, byte[] data, Optional externalSignature) { - var buffer = - ByteBuffer.allocate( - HEADER_SIZE - + data.length - + nextPubKey.toBytes().length - + externalSignature.map((a) -> a.getSignature().length).orElse(0)) - .order(ByteOrder.LITTLE_ENDIAN); - buffer.put(data); - externalSignature.ifPresent(signature -> buffer.put(signature.getSignature())); - buffer.putInt(nextPubKey.getAlgorithm().getNumber()); - buffer.put(nextPubKey.toBytes()); - buffer.flip(); - return buffer.array(); - } - - public static byte[] getBufferSealedSignature( - PublicKey nextPubKey, byte[] data, byte[] blockSignature) { - var buffer = - ByteBuffer.allocate( - HEADER_SIZE + data.length + nextPubKey.toBytes().length + blockSignature.length) - .order(ByteOrder.LITTLE_ENDIAN); - buffer.put(data); - buffer.putInt(nextPubKey.getAlgorithm().getNumber()); - buffer.put(nextPubKey.toBytes()); - buffer.put(blockSignature); - buffer.flip(); - return buffer.array(); + public static int blockSignatureVersion( + PublicKey blockKey, + PublicKey nextKey, + Optional externalSignature, + Optional blockVersion, + Stream previousSigVersions) { + if (externalSignature.isPresent()) { + return THIRD_PARTY_SIGNATURE_VERSION; + } + + if (blockVersion.isPresent() && blockVersion.get() >= SerializedBiscuit.DATALOG_3_3) { + return DATALOG_3_3_SIGNATURE_VERSION; + } + + if (blockKey.getAlgorithm() != Schema.PublicKey.Algorithm.Ed25519 + || nextKey.getAlgorithm() != Schema.PublicKey.Algorithm.Ed25519) { + return NON_ED25519_SIGNATURE_VERSION; + } + + return previousSigVersions.mapToInt(Integer::intValue).max().orElse(0); + } + + public static Either generateBlockSignaturePayload( + byte[] payload, + PublicKey nextKey, + Optional externalSignature, + Optional previousSignature, + int version) { + switch (version) { + case 0: + return Right(generateBlockSignaturePayloadV0(payload, nextKey, externalSignature)); + case 1: + return Right( + generateBlockSignaturePayloadV1( + payload, nextKey, externalSignature, previousSignature, version)); + default: + return Left( + new Error.FormatError.DeserializationError("unsupported block version " + version)); + } + } + + public static byte[] generateBlockSignaturePayloadV0( + byte[] payload, PublicKey nextKey, Optional externalSignature) { + var nextKeyBytes = nextKey.toBytes(); + var capacity = payload.length + Integer.BYTES + nextKeyBytes.length; + if (externalSignature.isPresent()) { + capacity += externalSignature.get().getSignature().length; + } + var toVerify = ByteBuffer.allocate(capacity).order(ByteOrder.LITTLE_ENDIAN); + toVerify.put(payload); + if (externalSignature.isPresent()) { + toVerify.put(externalSignature.get().getSignature()); + } + toVerify.putInt(nextKey.getAlgorithm().getNumber()); + toVerify.put(nextKeyBytes); + toVerify.flip(); + return toVerify.array(); + } + + public static byte[] generateBlockSignaturePayloadV1( + byte[] payload, + PublicKey nextKey, + Optional externalSignature, + Optional previousSignature, + int version) { + var nextKeyBytes = nextKey.toBytes(); + var capacity = + BLOCK_VERSION.length + + Integer.BYTES + + PAYLOAD.length + + payload.length + + ALGORITHM.length + + Integer.BYTES + + NEXTKEY.length + + nextKeyBytes.length; + if (previousSignature.isPresent()) { + capacity += PREVSIG.length + previousSignature.get().length; + } + if (externalSignature.isPresent()) { + capacity += EXTERNALSIG.length + externalSignature.get().getSignature().length; + } + + var toVerify = ByteBuffer.allocate(capacity).order(ByteOrder.LITTLE_ENDIAN); + toVerify.put(BLOCK_VERSION); + toVerify.putInt(version); + toVerify.put(PAYLOAD); + toVerify.put(payload); + toVerify.put(ALGORITHM); + toVerify.putInt(nextKey.getAlgorithm().getNumber()); + toVerify.put(NEXTKEY); + toVerify.put(nextKeyBytes); + if (previousSignature.isPresent()) { + toVerify.put(PREVSIG); + toVerify.put(previousSignature.get()); + } + if (externalSignature.isPresent()) { + toVerify.put(EXTERNALSIG); + toVerify.put(externalSignature.get().getSignature()); + } + toVerify.flip(); + return toVerify.array(); + } + + public static byte[] generateExternalBlockSignaturePayload( + byte[] payload, PublicKey previousKey, byte[] previousSignature, int version) { + if (version == 0) { + return generateExternalBlockSignaturePayloadV0(payload, previousKey); + } else { + return generateExternalBlockSignaturePayloadV1(payload, previousSignature, version); + } + } + + public static byte[] generateExternalBlockSignaturePayloadV0( + byte[] payload, PublicKey previousKey) { + var previousKeyBytes = previousKey.toBytes(); + var capacity = payload.length + Integer.BYTES + previousKeyBytes.length; + var toVerify = ByteBuffer.allocate(capacity).order(ByteOrder.LITTLE_ENDIAN); + toVerify.put(payload); + toVerify.putInt(previousKey.getAlgorithm().getNumber()); + toVerify.put(previousKey.toBytes()); + toVerify.flip(); + return toVerify.array(); + } + + public static byte[] generateExternalBlockSignaturePayloadV1( + byte[] payload, byte[] previousSignature, int version) { + var capacity = + EXTERNAL_VERSION.length + + Integer.BYTES + + PAYLOAD.length + + payload.length + + PREVSIG.length + + previousSignature.length; + var toVerify = ByteBuffer.allocate(capacity).order(ByteOrder.LITTLE_ENDIAN); + toVerify.put(EXTERNAL_VERSION); + toVerify.putInt(version); + toVerify.put(PAYLOAD); + toVerify.put(payload); + toVerify.put(PREVSIG); + toVerify.put(previousSignature); + toVerify.flip(); + return toVerify.array(); + } + + public static byte[] generateSealBlockSignaturePayloadV0(SignedBlock block) { + var keyBytes = block.getKey().toBytes(); + var capacity = + block.getBlock().length + Integer.BYTES + keyBytes.length + block.getSignature().length; + var toVerify = ByteBuffer.allocate(capacity).order(ByteOrder.LITTLE_ENDIAN); + toVerify.put(block.getBlock()); + toVerify.putInt(block.getKey().getAlgorithm().getNumber()); + toVerify.put(keyBytes); + toVerify.put(block.getSignature()); + toVerify.flip(); + return toVerify.array(); } } diff --git a/src/main/java/org/eclipse/biscuit/crypto/Token.java b/src/main/java/org/eclipse/biscuit/crypto/Token.java index 2ace9a61..65951e7a 100644 --- a/src/main/java/org/eclipse/biscuit/crypto/Token.java +++ b/src/main/java/org/eclipse/biscuit/crypto/Token.java @@ -13,6 +13,7 @@ import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.util.ArrayList; +import java.util.Optional; import org.eclipse.biscuit.error.Error; class Token { @@ -29,7 +30,9 @@ class Token { this.keys = new ArrayList<>(); this.keys.add(next.getPublicKey()); this.signatures = new ArrayList<>(); - byte[] payload = BlockSignatureBuffer.getBufferSignature(next.getPublicKey(), message); + byte[] payload = + BlockSignatureBuffer.generateBlockSignaturePayloadV0( + message, next.getPublicKey(), Optional.empty()); byte[] signature = rootSigner.sign(payload); this.signatures.add(signature); this.next = next; @@ -48,7 +51,9 @@ class Token { Token append(KeyPair keyPair, byte[] message) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException { - byte[] payload = BlockSignatureBuffer.getBufferSignature(keyPair.getPublicKey(), message); + byte[] payload = + BlockSignatureBuffer.generateBlockSignaturePayloadV0( + message, keyPair.getPublicKey(), Optional.empty()); byte[] signature = this.next.sign(payload); Token token = new Token(this.blocks, this.keys, this.signatures, keyPair); @@ -68,7 +73,8 @@ public Either verify(PublicKey root) PublicKey nextKey = this.keys.get(i); byte[] signature = this.signatures.get(i); - byte[] payload = BlockSignatureBuffer.getBufferSignature(nextKey, block); + byte[] payload = + BlockSignatureBuffer.generateBlockSignaturePayloadV0(block, nextKey, Optional.empty()); if (currentKey.verify(payload, signature)) { currentKey = nextKey; } else { diff --git a/src/main/java/org/eclipse/biscuit/token/Block.java b/src/main/java/org/eclipse/biscuit/token/Block.java index f5933468..90ec8553 100644 --- a/src/main/java/org/eclipse/biscuit/token/Block.java +++ b/src/main/java/org/eclipse/biscuit/token/Block.java @@ -83,6 +83,7 @@ public Block( this.scopes = scopes; this.publicKeys = publicKeys; this.externalKey = externalKey; + this.version = version; } public SymbolTable getSymbolTable() { @@ -435,7 +436,10 @@ public boolean equals(Object o) { if (!Objects.equals(publicKeys, block.publicKeys)) { return false; } - return Objects.equals(externalKey, block.externalKey); + if (!Objects.equals(externalKey, block.externalKey)) { + return false; + } + return Objects.equals(version, block.version); } @Override @@ -448,6 +452,7 @@ public int hashCode() { result = 31 * result + (scopes != null ? scopes.hashCode() : 0); result = 31 * result + (publicKeys != null ? publicKeys.hashCode() : 0); result = 31 * result + (externalKey != null ? externalKey.hashCode() : 0); + result = 31 * result + Long.hashCode(version); return result; } @@ -471,6 +476,8 @@ public String toString() { + publicKeys + ", externalKey=" + externalKey + + ", version=" + + version + '}'; } diff --git a/src/main/java/org/eclipse/biscuit/token/ThirdPartyBlockRequest.java b/src/main/java/org/eclipse/biscuit/token/ThirdPartyBlockRequest.java index 7613ec68..e1f5f824 100644 --- a/src/main/java/org/eclipse/biscuit/token/ThirdPartyBlockRequest.java +++ b/src/main/java/org/eclipse/biscuit/token/ThirdPartyBlockRequest.java @@ -6,6 +6,7 @@ package org.eclipse.biscuit.token; import biscuit.format.schema.Schema; +import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import io.vavr.control.Either; import io.vavr.control.Option; @@ -14,7 +15,7 @@ import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; -import java.util.Objects; +import java.util.Arrays; import org.eclipse.biscuit.crypto.BlockSignatureBuffer; import org.eclipse.biscuit.crypto.PublicKey; import org.eclipse.biscuit.crypto.Signer; @@ -23,10 +24,10 @@ import org.eclipse.biscuit.token.builder.Block; public final class ThirdPartyBlockRequest { - private final PublicKey previousKey; + private final byte[] previousSignature; - ThirdPartyBlockRequest(PublicKey previousKey) { - this.previousKey = previousKey; + ThirdPartyBlockRequest(byte[] previousSignature) { + this.previousSignature = previousSignature; } public Either createBlock( @@ -42,7 +43,11 @@ public Either createBlock( } byte[] serializedBlock = res.get(); - byte[] payload = BlockSignatureBuffer.getBufferSignature(this.previousKey, serializedBlock); + byte[] payload = + BlockSignatureBuffer.generateExternalBlockSignaturePayloadV1( + serializedBlock, + this.previousSignature, + BlockSignatureBuffer.THIRD_PARTY_SIGNATURE_VERSION); byte[] signature = externalSigner.sign(payload); PublicKey publicKey = externalSigner.getPublicKey(); @@ -52,15 +57,29 @@ public Either createBlock( public Schema.ThirdPartyBlockRequest serialize() throws Error.FormatError.SerializationError { Schema.ThirdPartyBlockRequest.Builder b = Schema.ThirdPartyBlockRequest.newBuilder(); - b.setPreviousKey(this.previousKey.serialize()); + b.setPreviousSignature(ByteString.copyFrom(this.previousSignature)); return b.build(); } public static ThirdPartyBlockRequest deserialize(Schema.ThirdPartyBlockRequest b) throws Error.FormatError.DeserializationError { - PublicKey previousKey = PublicKey.deserialize(b.getPreviousKey()); - return new ThirdPartyBlockRequest(previousKey); + + if (b.hasLegacyPreviousKey()) { + throw new Error.FormatError.DeserializationError( + "public keys were provided in third-party block request"); + } + if (b.getLegacyPublicKeysCount() > 0) { + throw new Error.FormatError.DeserializationError( + "public keys were provided in third-party block request"); + } + + if (!b.hasPreviousSignature()) { + throw new Error.FormatError.DeserializationError( + "missing previous signature in third-party block request"); + } + + return new ThirdPartyBlockRequest(b.getPreviousSignature().toByteArray()); } public static ThirdPartyBlockRequest fromBytes(byte[] slice) @@ -86,16 +105,16 @@ public boolean equals(Object o) { ThirdPartyBlockRequest that = (ThirdPartyBlockRequest) o; - return Objects.equals(previousKey, that.previousKey); + return Arrays.equals(previousSignature, that.previousSignature); } @Override public int hashCode() { - return previousKey != null ? previousKey.hashCode() : 0; + return previousSignature != null ? Arrays.hashCode(previousSignature) : 0; } @Override public String toString() { - return "ThirdPartyBlockRequest{previousKey=" + previousKey + '}'; + return "ThirdPartyBlockRequest{previousSignature=" + previousSignature + '}'; } } diff --git a/src/main/java/org/eclipse/biscuit/token/UnverifiedBiscuit.java b/src/main/java/org/eclipse/biscuit/token/UnverifiedBiscuit.java index e1ada075..549356ed 100644 --- a/src/main/java/org/eclipse/biscuit/token/UnverifiedBiscuit.java +++ b/src/main/java/org/eclipse/biscuit/token/UnverifiedBiscuit.java @@ -27,6 +27,7 @@ import org.eclipse.biscuit.error.Error; import org.eclipse.biscuit.token.format.ExternalSignature; import org.eclipse.biscuit.token.format.SerializedBiscuit; +import org.eclipse.biscuit.token.format.SignedBlock; /** * UnverifiedBiscuit auth token. UnverifiedBiscuit means it's deserialized without checking @@ -236,6 +237,10 @@ public Option getRootKeyId() { return this.serializedBiscuit.getRootKeyId(); } + public SerializedBiscuit getContainer() { + return this.serializedBiscuit; + } + public int blockCount() { return 1 + blocks.size(); } @@ -258,44 +263,43 @@ public List blockPublicKeys(int index) { /** Generates a third party block request from a token */ public ThirdPartyBlockRequest thirdPartyRequest() { - PublicKey previousKey; + byte[] previousSignature; if (this.serializedBiscuit.getBlocks().isEmpty()) { - previousKey = this.serializedBiscuit.getAuthority().getKey(); + previousSignature = this.serializedBiscuit.getAuthority().getSignature(); } else { - previousKey = + previousSignature = this.serializedBiscuit .getBlocks() .get(this.serializedBiscuit.getBlocks().size() - 1) - .getKey(); + .getSignature(); } - return new ThirdPartyBlockRequest(previousKey); + return new ThirdPartyBlockRequest(previousSignature); } /** Generates a third party block request from a token */ public UnverifiedBiscuit appendThirdPartyBlock( PublicKey externalKey, ThirdPartyBlockContents blockResponse) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException, Error { - PublicKey previousKey; + SignedBlock previousBlock; if (this.serializedBiscuit.getBlocks().isEmpty()) { - previousKey = this.serializedBiscuit.getAuthority().getKey(); + previousBlock = this.serializedBiscuit.getAuthority(); } else { - previousKey = - this.serializedBiscuit - .getBlocks() - .get(this.serializedBiscuit.getBlocks().size() - 1) - .getKey(); + previousBlock = + this.serializedBiscuit.getBlocks().get(this.serializedBiscuit.getBlocks().size() - 1); } - KeyPair nextKeyPair = KeyPair.generate(previousKey.getAlgorithm()); + KeyPair nextKeyPair = KeyPair.generate(previousBlock.getKey().getAlgorithm()); byte[] payload = - BlockSignatureBuffer.getBufferSignature(previousKey, blockResponse.getPayload()); + BlockSignatureBuffer.generateExternalBlockSignaturePayloadV1( + blockResponse.getPayload(), + previousBlock.getSignature(), + BlockSignatureBuffer.THIRD_PARTY_SIGNATURE_VERSION); if (!externalKey.verify(payload, blockResponse.getSignature())) { throw new Error.FormatError.Signature.InvalidSignature( "signature error: Verification equation was not satisfied"); } - Either res = - Block.fromBytes(blockResponse.getPayload(), Option.some(externalKey)); + var res = Block.fromBytes(blockResponse.getPayload(), Option.some(externalKey)); if (res.isLeft()) { throw res.getLeft(); } @@ -307,7 +311,7 @@ public UnverifiedBiscuit appendThirdPartyBlock( UnverifiedBiscuit copiedBiscuit = this.copy(); - Either containerRes = + var containerRes = copiedBiscuit.serializedBiscuit.append(nextKeyPair, block, Option.some(externalSignature)); if (containerRes.isLeft()) { throw containerRes.getLeft(); 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 5424f070..25dcc19e 100644 --- a/src/main/java/org/eclipse/biscuit/token/format/SerializedBiscuit.java +++ b/src/main/java/org/eclipse/biscuit/token/format/SerializedBiscuit.java @@ -16,13 +16,13 @@ import io.vavr.control.Option; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.util.ArrayList; import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; import org.eclipse.biscuit.crypto.BlockSignatureBuffer; import org.eclipse.biscuit.crypto.KeyDelegate; import org.eclipse.biscuit.crypto.KeyPair; @@ -39,8 +39,17 @@ public final class SerializedBiscuit { private Proof proof; private Option rootKeyId; + // minimum supported version of the serialization format public static final int MIN_SCHEMA_VERSION = 3; + // maximum supported version of the serialization format public static final int MAX_SCHEMA_VERSION = 5; + // starting version for datalog 3.1 features (check all, bitwise operators, !=, …) + public static final int DATALOG_3_1 = 4; + // starting version for 3rd party blocks (datalog 3.2) + public static final int DATALOG_3_2 = 5; + // starting version for datalog 3.3 features (reject if, closures, array/map, null, external + // functions, …) + public static final int DATALOG_3_3 = 6; /** * Deserializes a SerializedBiscuit from a byte array @@ -137,7 +146,8 @@ private static SerializedBiscuit deserialize(Schema.Biscuit data) data.getAuthority().getBlock().toByteArray(), PublicKey.deserialize(data.getAuthority().getNextKey()), data.getAuthority().getSignature().toByteArray(), - Option.none()); + Option.none(), + data.getAuthority().getVersion()); ArrayList blocks = new ArrayList<>(); for (Schema.SignedBlock block : data.getBlocksList()) { @@ -156,7 +166,8 @@ private static SerializedBiscuit deserialize(Schema.Biscuit data) block.getBlock().toByteArray(), PublicKey.deserialize(block.getNextKey()), block.getSignature().toByteArray(), - external)); + external, + block.getVersion())); } // One flags between hasNextSecret() and hasFinalSignature() needs to be set @@ -199,6 +210,9 @@ public byte[] serialize() throws Error.FormatError.SerializationError { authorityBuilder.setBlock(ByteString.copyFrom(authorityBlock.getBlock())); authorityBuilder.setNextKey(authorityBlock.getKey().serialize()); authorityBuilder.setSignature(ByteString.copyFrom(authorityBlock.getSignature())); + if (authorityBlock.getVersion() > 0) { + authorityBuilder.setVersion(authorityBlock.getVersion()); + } Schema.Biscuit.Builder biscuitBuilder = Schema.Biscuit.newBuilder(); biscuitBuilder.setAuthority(authorityBuilder.build()); @@ -207,6 +221,9 @@ public byte[] serialize() throws Error.FormatError.SerializationError { blockBuilder.setBlock(ByteString.copyFrom(b.getBlock())); blockBuilder.setNextKey(b.getKey().serialize()); blockBuilder.setSignature(ByteString.copyFrom(b.getSignature())); + if (b.getVersion() > 0) { + blockBuilder.setVersion(b.getVersion()); + } if (b.getExternalSignature().isDefined()) { ExternalSignature externalSignature = b.getExternalSignature().get(); @@ -263,9 +280,22 @@ public static Either make( b.writeTo(stream); byte[] block = stream.toByteArray(); PublicKey nextKey = next.getPublicKey(); - byte[] payload = BlockSignatureBuffer.getBufferSignature(nextKey, block); - byte[] signature = rootSigner.sign(payload); - SignedBlock signedBlock = new SignedBlock(block, nextKey, signature, Option.none()); + int blockSignatureVersion = + BlockSignatureBuffer.blockSignatureVersion( + rootSigner.getPublicKey(), + next.getPublicKey(), + Optional.empty(), + Optional.of(authority.getVersion()), + Stream.empty()); + var payload = + BlockSignatureBuffer.generateBlockSignaturePayload( + block, nextKey, Optional.empty(), Optional.empty(), blockSignatureVersion); + if (payload.isLeft()) { + return Left(payload.getLeft()); + } + byte[] signature = rootSigner.sign(payload.get()); + SignedBlock signedBlock = + new SignedBlock(block, nextKey, signature, Option.none(), blockSignatureVersion); Proof proof = new Proof.NextSecret(next); return Right(new SerializedBiscuit(signedBlock, new ArrayList<>(), proof, rootKeyId)); @@ -286,15 +316,33 @@ public Either append( b.writeTo(stream); byte[] block = stream.toByteArray(); - KeyPair secretKey = this.proof.secretKey(); PublicKey nextKey = next.getPublicKey(); - byte[] payload = - BlockSignatureBuffer.getBufferSignature( - nextKey, block, externalSignature.toJavaOptional()); - byte[] signature = this.proof.secretKey().sign(payload); + int blockSignatureVersion = + BlockSignatureBuffer.blockSignatureVersion( + proof.secretKey().getPublicKey(), + next.getPublicKey(), + externalSignature.toJavaOptional(), + Optional.of(newBlock.getVersion()), + this.blocks.stream().map(SignedBlock::getVersion)); + var payload = + BlockSignatureBuffer.generateBlockSignaturePayload( + block, + nextKey, + externalSignature.toJavaOptional(), + Optional.of( + this.blocks.isEmpty() + ? this.authority.getSignature() + : this.blocks.get(this.blocks.size() - 1).getSignature()), + blockSignatureVersion); + if (payload.isLeft()) { + return Left(payload.getLeft()); + } + + byte[] signature = this.proof.secretKey().sign(payload.get()); - SignedBlock signedBlock = new SignedBlock(block, nextKey, signature, externalSignature); + SignedBlock signedBlock = + new SignedBlock(block, nextKey, signature, externalSignature, blockSignatureVersion); ArrayList blocks = new ArrayList<>(); for (SignedBlock bl : this.blocks) { @@ -313,17 +361,19 @@ public Either append( public Either verify(PublicKey root) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { PublicKey currentKey = root; - Either res = verifyBlockSignature(this.authority, currentKey); + Either res = verifyAuthorityBlockSignature(this.authority, currentKey); if (res.isRight()) { currentKey = res.get(); } else { return Left(res.getLeft()); } + var previousSignature = this.authority.getSignature(); for (SignedBlock b : this.blocks) { - res = verifyBlockSignature(b, currentKey); + res = verifyBlockSignature(b, currentKey, previousSignature); if (res.isRight()) { currentKey = res.get(); + previousSignature = b.getSignature(); } else { return Left(res.getLeft()); } @@ -358,12 +408,7 @@ public Either verify(PublicKey root) b = this.blocks.get(this.blocks.size() - 1); } - byte[] block = b.getBlock(); - PublicKey nextKey = b.getKey(); - byte[] signature = b.getSignature(); - - byte[] payload = BlockSignatureBuffer.getBufferSealedSignature(nextKey, block, signature); - + byte[] payload = BlockSignatureBuffer.generateSealBlockSignaturePayloadV0(b); if (currentKey.verify(payload, finalSignature)) { return Right(null); } else { @@ -372,34 +417,67 @@ public Either verify(PublicKey root) } } - static Either verifyBlockSignature(SignedBlock signedBlock, PublicKey publicKey) + static Either verifyAuthorityBlockSignature( + SignedBlock signedBlock, PublicKey publicKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { + var signatureLengthError = + PublicKey.validateSignatureLength( + publicKey.getAlgorithm(), signedBlock.getSignature().length); + if (signatureLengthError.isPresent()) { + return Left(signatureLengthError.get()); + } - PublicKey nextKey = signedBlock.getKey(); - byte[] signature = signedBlock.getSignature(); + var payload = + BlockSignatureBuffer.generateBlockSignaturePayload( + signedBlock.getBlock(), + signedBlock.getKey(), + signedBlock.getExternalSignature().toJavaOptional(), + Optional.empty(), + signedBlock.getVersion()); + if (payload.isLeft()) { + return Left(payload.getLeft()); + } + + if (!publicKey.verify(payload.get(), signedBlock.getSignature())) { + return Left( + new Error.FormatError.Signature.InvalidSignature( + "signature error: Verification equation was not satisfied")); + } + + return Right(signedBlock.getKey()); + } + static Either verifyBlockSignature( + SignedBlock signedBlock, PublicKey publicKey, byte[] previousSignature) + throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { var signatureLengthError = - PublicKey.validateSignatureLength(publicKey.getAlgorithm(), signature.length); + PublicKey.validateSignatureLength( + publicKey.getAlgorithm(), signedBlock.getSignature().length); if (signatureLengthError.isPresent()) { return Left(signatureLengthError.get()); } - ByteBuffer algoBuf = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN); - algoBuf.putInt(Integer.valueOf(nextKey.getAlgorithm().getNumber())); - algoBuf.flip(); + var payload = + BlockSignatureBuffer.generateBlockSignaturePayload( + signedBlock.getBlock(), + signedBlock.getKey(), + signedBlock.getExternalSignature().toJavaOptional(), + Optional.of(previousSignature), + signedBlock.getVersion()); + if (payload.isLeft()) { + return Left(payload.getLeft()); + } - byte[] block = signedBlock.getBlock(); - byte[] payload = - BlockSignatureBuffer.getBufferSignature( - nextKey, block, signedBlock.getExternalSignature().toJavaOptional()); - if (!publicKey.verify(payload, signature)) { + if (!publicKey.verify(payload.get(), signedBlock.getSignature())) { return Left( new Error.FormatError.Signature.InvalidSignature( "signature error: Verification equation was not satisfied")); } if (signedBlock.getExternalSignature().isDefined()) { - byte[] externalPayload = BlockSignatureBuffer.getBufferSignature(publicKey, block); + byte[] externalPayload = + BlockSignatureBuffer.generateExternalBlockSignaturePayload( + signedBlock.getBlock(), publicKey, previousSignature, signedBlock.getVersion()); ExternalSignature externalSignature = signedBlock.getExternalSignature().get(); if (!externalSignature.getKey().verify(externalPayload, externalSignature.getSignature())) { @@ -409,7 +487,7 @@ static Either verifyBlockSignature(SignedBlock signedBlock, Pu } } - return Right(nextKey); + return Right(signedBlock.getKey()); } public Tuple2> extractBlocks(SymbolTable symbolTable) throws Error { @@ -475,9 +553,7 @@ public Either seal() } KeyPair secretKey = this.proof.secretKey(); - byte[] payload = - BlockSignatureBuffer.getBufferSealedSignature( - block.getKey(), block.getBlock(), block.getSignature()); + byte[] payload = BlockSignatureBuffer.generateSealBlockSignaturePayloadV0(block); byte[] signature = secretKey.sign(payload); this.proof = new Proof.FinalSignature(signature); diff --git a/src/main/java/org/eclipse/biscuit/token/format/SignedBlock.java b/src/main/java/org/eclipse/biscuit/token/format/SignedBlock.java index 79b9284e..935ced35 100644 --- a/src/main/java/org/eclipse/biscuit/token/format/SignedBlock.java +++ b/src/main/java/org/eclipse/biscuit/token/format/SignedBlock.java @@ -13,13 +13,19 @@ public class SignedBlock { private PublicKey key; private byte[] signature; private Option externalSignature; + private int version; public SignedBlock( - byte[] block, PublicKey key, byte[] signature, Option externalSignature) { + byte[] block, + PublicKey key, + byte[] signature, + Option externalSignature, + int version) { this.block = block; this.key = key; this.signature = signature; this.externalSignature = externalSignature; + this.version = version; } public byte[] getBlock() { @@ -37,4 +43,8 @@ public byte[] getSignature() { public Option getExternalSignature() { return externalSignature; } + + public int getVersion() { + return version; + } } diff --git a/src/main/proto/schema.proto b/src/main/proto/schema.proto index 641b4cf7..c52f49ad 100644 --- a/src/main/proto/schema.proto +++ b/src/main/proto/schema.proto @@ -14,6 +14,7 @@ message SignedBlock { required PublicKey nextKey = 2; required bytes signature = 3; optional ExternalSignature externalSignature = 4; + optional uint32 version = 5; } message ExternalSignature { @@ -32,7 +33,6 @@ message PublicKey { required bytes key = 2; } - message Proof { oneof Content { bytes nextSecret = 1; @@ -81,6 +81,7 @@ message CheckV2 { enum Kind { One = 0; All = 1; + Reject = 2; } } @@ -98,6 +99,9 @@ message TermV2 { bytes bytes = 5; bool bool = 6; TermSet set = 7; + Empty null = 8; + Array array = 9; + Map map = 10; } } @@ -105,6 +109,26 @@ message TermSet { repeated TermV2 set = 1; } +message Array { + repeated TermV2 array = 1; +} + +message Map { + repeated MapEntry entries = 1; +} + +message MapEntry { + required MapKey key = 1; + required TermV2 value = 2; +} + +message MapKey { + oneof Content { + int64 integer = 1; + uint64 string = 2; + } +} + message ExpressionV2 { repeated Op ops = 1; } @@ -114,6 +138,7 @@ message Op { TermV2 value = 1; OpUnary unary = 2; OpBinary Binary = 3; + OpClosure closure = 4; } } @@ -122,9 +147,12 @@ message OpUnary { Negate = 0; Parens = 1; Length = 2; + TypeOf = 3; + Ffi = 4; } required Kind kind = 1; + optional uint64 ffiName = 2; } message OpBinary { @@ -150,9 +178,24 @@ message OpBinary { BitwiseOr = 18; BitwiseXor = 19; NotEqual = 20; + HeterogeneousEqual = 21; + HeterogeneousNotEqual = 22; + LazyAnd = 23; + LazyOr = 24; + All = 25; + Any = 26; + Get = 27; + Ffi = 28; + Try = 29; } required Kind kind = 1; + optional uint64 ffiName = 2; +} + +message OpClosure { + repeated uint32 params = 1; + repeated Op ops = 2; } message Policy { @@ -175,8 +218,10 @@ message AuthorizerPolicies { } message ThirdPartyBlockRequest { - required PublicKey previousKey = 1; - repeated PublicKey publicKeys = 2; + optional PublicKey legacyPreviousKey = 1; + repeated PublicKey legacyPublicKeys = 2; + required bytes previousSignature = 3; + } message ThirdPartyBlockContents { @@ -229,4 +274,4 @@ message SnapshotBlock { repeated CheckV2 checks_v2 = 5; repeated Scope scope = 6; optional PublicKey externalKey = 7; -} \ No newline at end of file +} diff --git a/src/test/java/org/eclipse/biscuit/token/SamplesTest.java b/src/test/java/org/eclipse/biscuit/token/SamplesTest.java index 9edf8e8a..b788b253 100644 --- a/src/test/java/org/eclipse/biscuit/token/SamplesTest.java +++ b/src/test/java/org/eclipse/biscuit/token/SamplesTest.java @@ -313,6 +313,8 @@ class Block { @SuppressWarnings("checkstyle:MemberName") String external_key; + int version; + public List getSymbols() { return symbols; } diff --git a/src/test/resources/samples/README.md b/src/test/resources/samples/README.md index 1b0187dd..4f9608ed 100644 --- a/src/test/resources/samples/README.md +++ b/src/test/resources/samples/README.md @@ -13,6 +13,8 @@ symbols: ["file1", "file2"] public keys: [] +block version: 3 + ``` right("file1", "read"); right("file2", "read"); @@ -24,6 +26,8 @@ symbols: ["0"] public keys: [] +block version: 3 + ``` check if resource($0), operation("read"), right($0, "read"); ``` @@ -45,7 +49,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -53,7 +57,7 @@ World { "resource(\"file1\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -68,7 +72,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -96,6 +100,8 @@ symbols: ["file1"] public keys: [] +block version: 3 + ``` right("file1", "read"); ``` @@ -105,6 +111,8 @@ symbols: ["0"] public keys: [] +block version: 3 + ``` check if resource($0), operation("read"), right($0, "read"); ``` @@ -154,6 +162,8 @@ symbols: ["file1", "file2"] public keys: [] +block version: 3 + ``` right("file1", "read"); right("file2", "read"); @@ -165,6 +175,8 @@ symbols: ["0"] public keys: [] +block version: 3 + ``` check if resource($0), operation("read"), right($0, "read"); ``` @@ -184,6 +196,8 @@ symbols: ["file1", "file2"] public keys: [] +block version: 3 + ``` right("file1", "read"); right("file2", "read"); @@ -195,6 +209,8 @@ symbols: ["0"] public keys: [] +block version: 3 + ``` check if resource($0), operation("read"), right($0, "read"); ``` @@ -214,6 +230,8 @@ symbols: ["file1", "file2"] public keys: [] +block version: 3 + ``` right("file1", "read"); right("file2", "read"); @@ -225,6 +243,8 @@ symbols: ["0"] public keys: [] +block version: 3 + ``` check if resource($0), operation("read"), right($0, "read"); ``` @@ -234,6 +254,8 @@ symbols: [] public keys: [] +block version: 3 + ``` check if resource("file1"); ``` @@ -253,6 +275,8 @@ symbols: ["user_id", "alice", "file1"] public keys: [] +block version: 3 + ``` user_id("alice"); owner("alice", "file1"); @@ -263,6 +287,8 @@ symbols: ["0", "1"] public keys: [] +block version: 3 + ``` right($0, "read") <- resource($0), user_id($1), owner($1, $0); check if resource($0), operation("read"), right($0, "read"); @@ -273,6 +299,8 @@ symbols: ["file2"] public keys: [] +block version: 3 + ``` owner("alice", "file2"); ``` @@ -296,7 +324,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -305,7 +333,7 @@ World { "resource(\"file2\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -316,7 +344,7 @@ World { "user_id(\"alice\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 2, @@ -328,7 +356,7 @@ World { }, ] rules: [ - AuthorizerRuleSet { + Rules { origin: Some( 1, ), @@ -338,7 +366,7 @@ World { }, ] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -366,6 +394,8 @@ symbols: ["file1"] public keys: [] +block version: 3 + ``` right("file1", "read"); ``` @@ -375,6 +405,8 @@ symbols: ["0"] public keys: [] +block version: 3 + ``` check if resource($0), operation("read"), right($0, "read"); ``` @@ -384,6 +416,8 @@ symbols: ["file2"] public keys: [] +block version: 3 + ``` right("file2", "read"); ``` @@ -407,7 +441,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -416,7 +450,7 @@ World { "resource(\"file2\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -426,7 +460,7 @@ World { "right(\"file1\", \"read\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 2, @@ -439,7 +473,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -467,6 +501,8 @@ symbols: [] public keys: [] +block version: 3 + ``` ``` @@ -475,6 +511,8 @@ symbols: ["file1"] public keys: [] +block version: 3 + ``` check if resource("file1"); check if time($time), $time <= 2018-12-20T00:00:00Z; @@ -499,7 +537,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -512,7 +550,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -541,6 +579,8 @@ symbols: ["file1"] public keys: [] +block version: 3 + ``` right("file1", "read"); ``` @@ -550,6 +590,8 @@ symbols: ["file2"] public keys: [] +block version: 3 + ``` right("file2", "read"); ``` @@ -574,7 +616,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -583,7 +625,7 @@ World { "resource(\"file2\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -593,7 +635,7 @@ World { "right(\"file1\", \"read\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -606,7 +648,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -634,6 +676,8 @@ symbols: ["file1"] public keys: [] +block version: 3 + ``` right("file1", "read"); ``` @@ -657,7 +701,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -666,7 +710,7 @@ World { "resource(\"file2\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -679,7 +723,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -707,6 +751,8 @@ symbols: ["file1"] public keys: [] +block version: 3 + ``` check if resource("file1"); ``` @@ -728,7 +774,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -740,7 +786,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -773,7 +819,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -785,7 +831,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -986,6 +1032,8 @@ symbols: ["0", "file[0-9]+.txt"] public keys: [] +block version: 3 + ``` check if resource($0), $0.matches("file[0-9]+.txt"); ``` @@ -1006,7 +1054,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1017,7 +1065,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1049,7 +1097,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1060,7 +1108,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1088,6 +1136,8 @@ symbols: ["must_be_present", "hello"] public keys: [] +block version: 3 + ``` must_be_present("hello"); ``` @@ -1108,7 +1158,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1121,7 +1171,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -1149,6 +1199,8 @@ symbols: ["hello"] public keys: [] +block version: 3 + ``` check if resource("hello"); ``` @@ -1158,6 +1210,8 @@ symbols: ["test"] public keys: [] +block version: 3 + ``` query("test"); ``` @@ -1177,7 +1231,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -1190,7 +1244,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1346,6 +1400,8 @@ symbols: [] public keys: [] +block version: 3 + ``` check if operation("read"); ``` @@ -1355,6 +1411,8 @@ symbols: ["unbound", "any1", "any2"] public keys: [] +block version: 3 + ``` operation($unbound, "read") <- operation($any1, $any2); ``` @@ -1374,6 +1432,8 @@ symbols: [] public keys: [] +block version: 3 + ``` check if operation("read"); ``` @@ -1383,6 +1443,8 @@ symbols: ["any"] public keys: [] +block version: 3 + ``` operation("read") <- operation($any); ``` @@ -1404,7 +1466,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1412,7 +1474,7 @@ World { "operation(\"write\")", ], }, - AuthorizerFactSet { + Facts { origin: { None, Some( @@ -1425,7 +1487,7 @@ World { }, ] rules: [ - AuthorizerRuleSet { + Rules { origin: Some( 1, ), @@ -1435,7 +1497,7 @@ World { }, ] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1463,6 +1525,8 @@ symbols: ["file1", "file2"] public keys: [] +block version: 3 + ``` right("file1", "read"); right("file2", "read"); @@ -1474,6 +1538,8 @@ symbols: ["0"] public keys: [] +block version: 3 + ``` check if resource($0), operation("read"), right($0, "read"); ``` @@ -1496,7 +1562,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1505,7 +1571,7 @@ World { "resource(\"file1\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1520,7 +1586,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -1548,6 +1614,8 @@ symbols: ["ns::fact_123", "hello Ć©\t😁"] public keys: [] +block version: 3 + ``` ns::fact_123("hello Ć© 😁"); ``` @@ -1568,7 +1636,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1581,7 +1649,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -1609,6 +1677,8 @@ symbols: [] public keys: [] +block version: 3 + ``` read(0); write(1); @@ -1656,7 +1726,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1696,7 +1766,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -1724,6 +1794,8 @@ symbols: ["authority_fact"] public keys: [] +block version: 3 + ``` authority_fact(1); ``` @@ -1733,6 +1805,8 @@ symbols: ["block1_fact"] public keys: [] +block version: 3 + ``` block1_fact(1); ``` @@ -1742,6 +1816,8 @@ symbols: ["var"] public keys: [] +block version: 3 + ``` check if authority_fact($var); check if block1_fact($var); @@ -1763,7 +1839,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1773,7 +1849,7 @@ World { "authority_fact(1)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -1786,7 +1862,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 2, ), @@ -1815,6 +1891,8 @@ symbols: [] public keys: ["ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189"] +block version: 4 + ``` right("read"); check if group("admin") trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189; @@ -1827,6 +1905,8 @@ public keys: [] external signature by: "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189" +block version: 5 + ``` group("admin"); check if right("read"); @@ -1841,13 +1921,13 @@ allow if true; revocation ids: - `470e4bf7aa2a01ab39c98150bd06aa15b4aa5d86509044a8809a8634cd8cf2b42269a51a774b65d10bac9369d013070b00187925196a8e680108473f11cf8f03` -- `342167bc54bc642b6718a276875e55b6d39e9b21e4ce13b926a3d398b6c057fc436385bf4c817a16f9ecdf0b0d950e8b8258a20aeb3fd8896c5e9c1f0a53da03` +- `901b2af4dacf33458d2d91ac484b60bad948e8d10faa9695b096054d5b46e832a977b60b17464cacf545ad0801f549ea454675f0ac88c413406925e2af83ff08` authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1857,7 +1937,7 @@ World { "right(\"read\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -1870,7 +1950,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1878,7 +1958,7 @@ World { "check if group(\"admin\") trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -1898,6 +1978,7 @@ result: `Ok(0)` ------------------------------ +## block rules: test025_check_all.bc ## block rules: test025_check_all.bc ### token @@ -2033,6 +2114,8 @@ symbols: [] public keys: ["ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189"] +block version: 4 + ``` query(0); check if true trusting previous, ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189; @@ -2045,6 +2128,8 @@ public keys: ["ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7 external signature by: "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189" +block version: 5 + ``` query(1); query(1, 2) <- query(1), query(2) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463; @@ -2059,6 +2144,8 @@ public keys: ["ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7 external signature by: "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463" +block version: 5 + ``` query(2); check if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463; @@ -2072,6 +2159,8 @@ public keys: ["ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7 external signature by: "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463" +block version: 5 + ``` query(3); check if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463; @@ -2083,6 +2172,8 @@ symbols: [] public keys: ["ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136"] +block version: 4 + ``` query(4); check if query(2) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463; @@ -2103,16 +2194,16 @@ allow if true; revocation ids: - `3771cefe71beb21ead35a59c8116ee82627a5717c0295f35980662abccb159fe1b37848cb1818e548656bd4fd882d0094a2daab631c76b2b72e3a093914bfe04` -- `6528db2c9a561ada9086268549a600a8a52ff434ea8183812623eec0e9b6c5d3c41ab7868808623021d92294d583afdf92f4354bcdaa1bc50453e1b89afd630d` -- `5d5679fe69bfe74b7919323515e9ecba9d01422b16be9341b57f88e695b2bb0bd7966b781001d2b9e00ee618fdc239c96e17e32cb379f13f12d6bd7b1b47ad04` -- `c37bf24c063f0310eccab8864e48dbeffcdd7240b4f8d1e01eba4fc703e6c9082b845bb55543b10f008dc7f4e78540411912ac1f36fa2aa90011dca40f323b09` -- `3f675d6c364e06405d4868c904e40f3d81c32b083d91586db814d4cb4bf536b4ba209d82f11b4cb6da293b60b20d6122fc3e0e08e80c381dee83edd848211900` +- `7113d4dbb3b688b80e941f365a2c6342d480c77ed03937bccf85dc5cc3554c7517887b1b0c9021388a71e6ca9047aabaaad5ae5b511a2880902568444a98e50b` +- `d0e3fc4bbd1b7320022800af909585aa906f677c4ca79c275a10b6779f669384c464ee84a1b04f13877a25761a874748362c065f4d15a8cab5c5e16c34074403` +- `29b7e0a1f118a6185814a552660c516c43482044e280e7a8de85b8e7e54947e0ae82eb39d7b524d4b72cb9812a7a4b8871964f8f825b1c1ed85d344c05281d0d` +- `c0a505d4d921a8b2d0b885917d42e2bca87b5302d13249a61af6f3802af44d691c40a624f901d677724740cb974a188aeb1c3992c1565ac0fbec3aa4f68dac0a` authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -2122,7 +2213,7 @@ World { "query(0)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -2132,7 +2223,7 @@ World { "query(1)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -2145,7 +2236,7 @@ World { "query(1, 2)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 2, @@ -2155,7 +2246,7 @@ World { "query(2)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 3, @@ -2165,7 +2256,7 @@ World { "query(3)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 4, @@ -2177,7 +2268,7 @@ World { }, ] rules: [ - AuthorizerRuleSet { + Rules { origin: Some( 1, ), @@ -2187,7 +2278,7 @@ World { }, ] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -2195,7 +2286,7 @@ World { "check if true trusting previous, ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -2204,7 +2295,7 @@ World { "check if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 2, ), @@ -2213,7 +2304,7 @@ World { "check if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 3, ), @@ -2222,7 +2313,7 @@ World { "check if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 4, ), @@ -2231,7 +2322,7 @@ World { "check if query(4) trusting ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -2254,117 +2345,7 @@ result: `Ok(3)` ------------------------------ -## integer wraparound: test027_integer_wraparound.bc -### token - -authority: -symbols: [] - -public keys: [] - -``` -check if true || 10000000000 * 10000000000 != 0; -check if true || 9223372036854775807 + 1 != 0; -check if true || -9223372036854775808 - 1 != 0; -``` - -### validation - -authorizer code: -``` -allow if true; -``` - -revocation ids: -- `3346a22aae0abfc1ffa526f02f7650e90af909e5e519989026441e78cdc245b7fd126503cfdc8831325fc04307edc65238db319724477915f7040a2f6a719a05` - -authorizer world: -``` -World { - facts: [] - rules: [] - checks: [ - AuthorizerCheckSet { - origin: Some( - 0, - ), - checks: [ - "check if true || -9223372036854775808 - 1 != 0", - "check if true || 10000000000 * 10000000000 != 0", - "check if true || 9223372036854775807 + 1 != 0", - ], - }, -] - policies: [ - "allow if true", -] -} -``` - -result: `Err(Execution(Overflow))` - - ------------------------------- - -## test expression syntax and all available operations (v4 blocks): test028_expressions_v4.bc -### token - -authority: -symbols: ["abcD12x", "abcD12"] - -public keys: [] - -``` -check if 1 != 3; -check if 1 | 2 ^ 3 == 0; -check if "abcD12x" != "abcD12"; -check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z; -check if hex:12abcd != hex:12ab; -check if [1, 4] != [1, 2]; -``` - -### validation - -authorizer code: -``` -allow if true; -``` - -revocation ids: -- `117fa653744c859561555e6a6f5990e3a8e7817f91b87aa6991b6d64297158b4e884c92d10f49f74c96069df722aa676839b72751ca9d1fe83a7025b591de00b` - -authorizer world: -``` -World { - facts: [] - rules: [] - checks: [ - AuthorizerCheckSet { - origin: Some( - 0, - ), - checks: [ - "check if \"abcD12x\" != \"abcD12\"", - "check if 1 != 3", - "check if 1 | 2 ^ 3 == 0", - "check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z", - "check if [1, 4] != [1, 2]", - "check if hex:12abcd != hex:12ab", - ], - }, -] - policies: [ - "allow if true", -] -} -``` - -result: `Ok(0)` - - ------------------------------- - -## ECDSA secp256r1 signatures: test031_secp256r1.bc +## ECDSA secp256r1 signatures: test036_secp256r1.bc ### token authority: @@ -2372,6 +2353,8 @@ symbols: ["file1", "file2"] public keys: [] +block version: 3 + ``` right("file1", "read"); right("file2", "read"); @@ -2383,6 +2366,8 @@ symbols: ["0"] public keys: [] +block version: 3 + ``` check if resource($0), operation("read"), right($0, "read"); ``` @@ -2393,12 +2378,13 @@ authorizer code: ``` resource("file1"); operation("read"); + allow if true; ``` revocation ids: -- `760785de30d7348e9c847aab8b3bdad6a0d463f4f50ed9667aade563e9112ee6d2f589630dd7553c2eced2a57edf3636d5c874b35df15120c62fddcbdbd2de09` -- `30440220039667c7a4d964e4b449289dc8fd206d7aa0e77eb701a9253b3307d32c177fa8022023f7523c143c5fb55ee4cafe49804702ef05a70883ebf42185b54bd36a7e7cd4` +- `628b9a6d74cc80b3ece50befd1f5f0f025c0a35d51708b2e77c11aed5f968b93b4096c87ed8169605716de934e155443f140334d71708fcc4247e5a0a518b30d` +- `3046022100b60674854a12814cc36c8aab9600c1d9f9d3160e2334b72c0feede5a56213ea5022100a4f4bbf2dc33b309267af39fce76612017ddb6171e9cd2a3aa8a853f45f1675f` authorizer world: ``` @@ -2445,32 +2431,37 @@ World { result: `Ok(0)` + ------------------------------ -## ECDSA secp256r1 signatures: test036_secp256r1.bc +## ECDSA secp256r1 signature on third-party block: test037_secp256r1_third_party.bc ### token authority: -symbols: ["file1", "file2"] +symbols: ["file1", "file2", "from_third"] -public keys: [] +public keys: ["secp256r1/025e918fd4463832aea2823dfd9716a36b4d9b1377bd53dd82ddf4c0bc75ed6bbf"] -block version: 3 +block version: 4 ``` right("file1", "read"); right("file2", "read"); right("file1", "write"); +check if from_third(true) trusting secp256r1/025e918fd4463832aea2823dfd9716a36b4d9b1377bd53dd82ddf4c0bc75ed6bbf; ``` 1: -symbols: ["0"] +symbols: ["from_third", "0"] public keys: [] -block version: 3 +external signature by: "secp256r1/025e918fd4463832aea2823dfd9716a36b4d9b1377bd53dd82ddf4c0bc75ed6bbf" + +block version: 5 ``` +from_third(true); check if resource($0), operation("read"), right($0, "read"); ``` @@ -2485,8 +2476,8 @@ allow if true; ``` revocation ids: -- `628b9a6d74cc80b3ece50befd1f5f0f025c0a35d51708b2e77c11aed5f968b93b4096c87ed8169605716de934e155443f140334d71708fcc4247e5a0a518b30d` -- `3046022100b60674854a12814cc36c8aab9600c1d9f9d3160e2334b72c0feede5a56213ea5022100a4f4bbf2dc33b309267af39fce76612017ddb6171e9cd2a3aa8a853f45f1675f` +- `70f5402208516fd44cfc9df3dfcfc0a327ee9004f1801ed0a7abdcbbae923d566ddcd2d4a14f4622b35732c4e538af04075cc67ab0888fa2d8923cc668187f0f` +- `30450220793f95665d9af646339503a073670ea2c352459d2a2c2e14c57565f6c7eaf6bc022100cccadfc37e46755f52bb054ed206d7335067885df599a69431db40e33f33d4cf` authorizer world: ``` @@ -2513,9 +2504,27 @@ World { "right(\"file2\", \"read\")", ], }, + Facts { + origin: { + Some( + 1, + ), + }, + facts: [ + "from_third(true)", + ], + }, ] rules: [] checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if from_third(true) trusting secp256r1/025e918fd4463832aea2823dfd9716a36b4d9b1377bd53dd82ddf4c0bc75ed6bbf", + ], + }, Checks { origin: Some( 1, diff --git a/src/test/resources/samples/samples.json b/src/test/resources/samples/samples.json index 5c4989e8..77720256 100644 --- a/src/test/resources/samples/samples.json +++ b/src/test/resources/samples/samples.json @@ -13,7 +13,8 @@ ], "public_keys": [], "external_key": null, - "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n" + "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n", + "version": 3 }, { "symbols": [ @@ -21,7 +22,8 @@ ], "public_keys": [], "external_key": null, - "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n" + "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n", + "version": 3 } ], "validations": { @@ -98,7 +100,8 @@ ], "public_keys": [], "external_key": null, - "code": "right(\"file1\", \"read\");\n" + "code": "right(\"file1\", \"read\");\n", + "version": 3 }, { "symbols": [ @@ -106,7 +109,8 @@ ], "public_keys": [], "external_key": null, - "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n" + "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n", + "version": 3 } ], "validations": { @@ -174,7 +178,8 @@ ], "public_keys": [], "external_key": null, - "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n" + "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n", + "version": 3 }, { "symbols": [ @@ -182,7 +187,8 @@ ], "public_keys": [], "external_key": null, - "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n" + "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n", + "version": 3 } ], "validations": { @@ -213,7 +219,8 @@ ], "public_keys": [], "external_key": null, - "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n" + "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n", + "version": 3 }, { "symbols": [ @@ -221,7 +228,8 @@ ], "public_keys": [], "external_key": null, - "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n" + "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n", + "version": 3 } ], "validations": { @@ -252,7 +260,8 @@ ], "public_keys": [], "external_key": null, - "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n" + "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n", + "version": 3 }, { "symbols": [ @@ -260,13 +269,15 @@ ], "public_keys": [], "external_key": null, - "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n" + "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n", + "version": 3 }, { "symbols": [], "public_keys": [], "external_key": null, - "code": "check if resource(\"file1\");\n" + "code": "check if resource(\"file1\");\n", + "version": 3 } ], "validations": { @@ -298,7 +309,8 @@ ], "public_keys": [], "external_key": null, - "code": "user_id(\"alice\");\nowner(\"alice\", \"file1\");\n" + "code": "user_id(\"alice\");\nowner(\"alice\", \"file1\");\n", + "version": 3 }, { "symbols": [ @@ -307,7 +319,8 @@ ], "public_keys": [], "external_key": null, - "code": "right($0, \"read\") <- resource($0), user_id($1), owner($1, $0);\ncheck if resource($0), operation(\"read\"), right($0, \"read\");\n" + "code": "right($0, \"read\") <- resource($0), user_id($1), owner($1, $0);\ncheck if resource($0), operation(\"read\"), right($0, \"read\");\n", + "version": 3 }, { "symbols": [ @@ -315,7 +328,8 @@ ], "public_keys": [], "external_key": null, - "code": "owner(\"alice\", \"file2\");\n" + "code": "owner(\"alice\", \"file2\");\n", + "version": 3 } ], "validations": { @@ -408,7 +422,8 @@ ], "public_keys": [], "external_key": null, - "code": "right(\"file1\", \"read\");\n" + "code": "right(\"file1\", \"read\");\n", + "version": 3 }, { "symbols": [ @@ -416,7 +431,8 @@ ], "public_keys": [], "external_key": null, - "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n" + "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n", + "version": 3 }, { "symbols": [ @@ -424,7 +440,8 @@ ], "public_keys": [], "external_key": null, - "code": "right(\"file2\", \"read\");\n" + "code": "right(\"file2\", \"read\");\n", + "version": 3 } ], "validations": { @@ -507,7 +524,8 @@ "symbols": [], "public_keys": [], "external_key": null, - "code": "" + "code": "", + "version": 3 }, { "symbols": [ @@ -515,7 +533,8 @@ ], "public_keys": [], "external_key": null, - "code": "check if resource(\"file1\");\ncheck if time($time), $time <= 2018-12-20T00:00:00Z;\n" + "code": "check if resource(\"file1\");\ncheck if time($time), $time <= 2018-12-20T00:00:00Z;\n", + "version": 3 } ], "validations": { @@ -585,7 +604,8 @@ ], "public_keys": [], "external_key": null, - "code": "right(\"file1\", \"read\");\n" + "code": "right(\"file1\", \"read\");\n", + "version": 3 }, { "symbols": [ @@ -593,7 +613,8 @@ ], "public_keys": [], "external_key": null, - "code": "right(\"file2\", \"read\");\n" + "code": "right(\"file2\", \"read\");\n", + "version": 3 } ], "validations": { @@ -676,7 +697,8 @@ ], "public_keys": [], "external_key": null, - "code": "right(\"file1\", \"read\");\n" + "code": "right(\"file1\", \"read\");\n", + "version": 3 } ], "validations": { @@ -750,7 +772,8 @@ ], "public_keys": [], "external_key": null, - "code": "check if resource(\"file1\");\n" + "code": "check if resource(\"file1\");\n", + "version": 3 } ], "validations": { @@ -1009,7 +1032,8 @@ ], "public_keys": [], "external_key": null, - "code": "check if resource($0), $0.matches(\"file[0-9]+.txt\");\n" + "code": "check if resource($0), $0.matches(\"file[0-9]+.txt\");\n", + "version": 3 } ], "validations": { @@ -1109,7 +1133,8 @@ ], "public_keys": [], "external_key": null, - "code": "must_be_present(\"hello\");\n" + "code": "must_be_present(\"hello\");\n", + "version": 3 } ], "validations": { @@ -1158,7 +1183,8 @@ ], "public_keys": [], "external_key": null, - "code": "check if resource(\"hello\");\n" + "code": "check if resource(\"hello\");\n", + "version": 3 }, { "symbols": [ @@ -1166,7 +1192,8 @@ ], "public_keys": [], "external_key": null, - "code": "query(\"test\");\n" + "code": "query(\"test\");\n", + "version": 3 } ], "validations": { @@ -1231,6 +1258,7 @@ "symbols": [ "hello world", "hello", + "hello", "world", "aaabde", "a*c?.e", @@ -1323,7 +1351,8 @@ "symbols": [], "public_keys": [], "external_key": null, - "code": "check if operation(\"read\");\n" + "code": "check if operation(\"read\");\n", + "version": 3 }, { "symbols": [ @@ -1333,7 +1362,8 @@ ], "public_keys": [], "external_key": null, - "code": "operation($unbound, \"read\") <- operation($any1, $any2);\n" + "code": "operation($unbound, \"read\") <- operation($any1, $any2);\n", + "version": 3 } ], "validations": { @@ -1365,7 +1395,8 @@ "symbols": [], "public_keys": [], "external_key": null, - "code": "check if operation(\"read\");\n" + "code": "check if operation(\"read\");\n", + "version": 3 }, { "symbols": [ @@ -1373,7 +1404,8 @@ ], "public_keys": [], "external_key": null, - "code": "operation(\"read\") <- operation($any);\n" + "code": "operation(\"read\") <- operation($any);\n", + "version": 3 } ], "validations": { @@ -1457,7 +1489,8 @@ ], "public_keys": [], "external_key": null, - "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n" + "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n", + "version": 3 }, { "symbols": [ @@ -1465,7 +1498,8 @@ ], "public_keys": [], "external_key": null, - "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n" + "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n", + "version": 3 } ], "validations": { @@ -1527,7 +1561,8 @@ ], "public_keys": [], "external_key": null, - "code": "ns::fact_123(\"hello Ć©\t😁\");\n" + "code": "ns::fact_123(\"hello Ć©\t😁\");\n", + "version": 3 } ], "validations": { @@ -1574,7 +1609,8 @@ "symbols": [], "public_keys": [], "external_key": null, - "code": "read(0);\nwrite(1);\nresource(2);\noperation(3);\nright(4);\ntime(5);\nrole(6);\nowner(7);\ntenant(8);\nnamespace(9);\nuser(10);\nteam(11);\nservice(12);\nadmin(13);\nemail(14);\ngroup(15);\nmember(16);\nip_address(17);\nclient(18);\nclient_ip(19);\ndomain(20);\npath(21);\nversion(22);\ncluster(23);\nnode(24);\nhostname(25);\nnonce(26);\nquery(27);\n" + "code": "read(0);\nwrite(1);\nresource(2);\noperation(3);\nright(4);\ntime(5);\nrole(6);\nowner(7);\ntenant(8);\nnamespace(9);\nuser(10);\nteam(11);\nservice(12);\nadmin(13);\nemail(14);\ngroup(15);\nmember(16);\nip_address(17);\nclient(18);\nclient_ip(19);\ndomain(20);\npath(21);\nversion(22);\ncluster(23);\nnode(24);\nhostname(25);\nnonce(26);\nquery(27);\n", + "version": 3 } ], "validations": { @@ -1650,7 +1686,8 @@ ], "public_keys": [], "external_key": null, - "code": "authority_fact(1);\n" + "code": "authority_fact(1);\n", + "version": 3 }, { "symbols": [ @@ -1658,7 +1695,8 @@ ], "public_keys": [], "external_key": null, - "code": "block1_fact(1);\n" + "code": "block1_fact(1);\n", + "version": 3 }, { "symbols": [ @@ -1666,7 +1704,8 @@ ], "public_keys": [], "external_key": null, - "code": "check if authority_fact($var);\ncheck if block1_fact($var);\n" + "code": "check if authority_fact($var);\ncheck if block1_fact($var);\n", + "version": 3 } ], "validations": { @@ -1743,13 +1782,15 @@ "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189" ], "external_key": null, - "code": "right(\"read\");\ncheck if group(\"admin\") trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n" + "code": "right(\"read\");\ncheck if group(\"admin\") trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n", + "version": 4 }, { "symbols": [], "public_keys": [], "external_key": "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189", - "code": "group(\"admin\");\ncheck if right(\"read\");\n" + "code": "group(\"admin\");\ncheck if right(\"read\");\n", + "version": 5 } ], "validations": { @@ -1798,7 +1839,7 @@ "authorizer_code": "allow if true;\n", "revocation_ids": [ "470e4bf7aa2a01ab39c98150bd06aa15b4aa5d86509044a8809a8634cd8cf2b42269a51a774b65d10bac9369d013070b00187925196a8e680108473f11cf8f03", - "342167bc54bc642b6718a276875e55b6d39e9b21e4ce13b926a3d398b6c057fc436385bf4c817a16f9ecdf0b0d950e8b8258a20aeb3fd8896c5e9c1f0a53da03" + "901b2af4dacf33458d2d91ac484b60bad948e8d10faa9695b096054d5b46e832a977b60b17464cacf545ad0801f549ea454675f0ac88c413406925e2af83ff08" ] } } @@ -1934,7 +1975,8 @@ "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189" ], "external_key": null, - "code": "query(0);\ncheck if true trusting previous, ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n" + "code": "query(0);\ncheck if true trusting previous, ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n", + "version": 4 }, { "symbols": [], @@ -1943,7 +1985,8 @@ "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" + "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", + "version": 5 }, { "symbols": [], @@ -1952,7 +1995,8 @@ "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" + "code": "query(2);\ncheck if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n", + "version": 5 }, { "symbols": [], @@ -1961,7 +2005,8 @@ "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" + "code": "query(3);\ncheck if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n", + "version": 5 }, { "symbols": [], @@ -1970,7 +2015,8 @@ "ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136" ], "external_key": null, - "code": "query(4);\ncheck if query(2) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(4) trusting ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136;\n" + "code": "query(4);\ncheck if query(2) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(4) trusting ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136;\n", + "version": 4 } ], "validations": { @@ -2090,85 +2136,68 @@ "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", - "6528db2c9a561ada9086268549a600a8a52ff434ea8183812623eec0e9b6c5d3c41ab7868808623021d92294d583afdf92f4354bcdaa1bc50453e1b89afd630d", - "5d5679fe69bfe74b7919323515e9ecba9d01422b16be9341b57f88e695b2bb0bd7966b781001d2b9e00ee618fdc239c96e17e32cb379f13f12d6bd7b1b47ad04", - "c37bf24c063f0310eccab8864e48dbeffcdd7240b4f8d1e01eba4fc703e6c9082b845bb55543b10f008dc7f4e78540411912ac1f36fa2aa90011dca40f323b09", - "3f675d6c364e06405d4868c904e40f3d81c32b083d91586db814d4cb4bf536b4ba209d82f11b4cb6da293b60b20d6122fc3e0e08e80c381dee83edd848211900" + "7113d4dbb3b688b80e941f365a2c6342d480c77ed03937bccf85dc5cc3554c7517887b1b0c9021388a71e6ca9047aabaaad5ae5b511a2880902568444a98e50b", + "d0e3fc4bbd1b7320022800af909585aa906f677c4ca79c275a10b6779f669384c464ee84a1b04f13877a25761a874748362c065f4d15a8cab5c5e16c34074403", + "29b7e0a1f118a6185814a552660c516c43482044e280e7a8de85b8e7e54947e0ae82eb39d7b524d4b72cb9812a7a4b8871964f8f825b1c1ed85d344c05281d0d", + "c0a505d4d921a8b2d0b885917d42e2bca87b5302d13249a61af6f3802af44d691c40a624f901d677724740cb974a188aeb1c3992c1565ac0fbec3aa4f68dac0a" ] } } }, { - "title": "integer wraparound", - "filename": "test027_integer_wraparound.bc", + "title": "ECDSA secp256r1 signatures", + "filename": "test036_secp256r1.bc", "token": [ { - "symbols": [], + "symbols": [ + "file1", + "file2" + ], "public_keys": [], "external_key": null, - "code": "check if true || 10000000000 * 10000000000 != 0;\ncheck if true || 9223372036854775807 + 1 != 0;\ncheck if true || -9223372036854775808 - 1 != 0;\n" - } - ], - "validations": { - "": { - "world": { - "facts": [], - "rules": [], - "checks": [ - { - "origin": 0, - "checks": [ - "check if true || -9223372036854775808 - 1 != 0", - "check if true || 10000000000 * 10000000000 != 0", - "check if true || 9223372036854775807 + 1 != 0" - ] - } - ], - "policies": [ - "allow if true" - ] - }, - "result": { - "Err": { - "Execution": "Overflow" - } - }, - "authorizer_code": "allow if true;\n", - "revocation_ids": [ - "3346a22aae0abfc1ffa526f02f7650e90af909e5e519989026441e78cdc245b7fd126503cfdc8831325fc04307edc65238db319724477915f7040a2f6a719a05" - ] - } - } - }, - { - "title": "test expression syntax and all available operations (v4 blocks)", - "filename": "test028_expressions_v4.bc", - "token": [ + "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n", + "version": 3 + }, { "symbols": [ - "abcD12x", - "abcD12" + "0" ], "public_keys": [], "external_key": null, - "code": "check if 1 != 3;\ncheck if 1 | 2 ^ 3 == 0;\ncheck if \"abcD12x\" != \"abcD12\";\ncheck if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z;\ncheck if hex:12abcd != hex:12ab;\ncheck if [1, 4] != [1, 2];\n" + "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n", + "version": 3 } ], "validations": { "": { "world": { - "facts": [], + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "operation(\"read\")", + "resource(\"file1\")" + ] + }, + { + "origin": [ + 0 + ], + "facts": [ + "right(\"file1\", \"read\")", + "right(\"file1\", \"write\")", + "right(\"file2\", \"read\")" + ] + } + ], "rules": [], "checks": [ { - "origin": 0, + "origin": 1, "checks": [ - "check if \"abcD12x\" != \"abcD12\"", - "check if 1 != 3", - "check if 1 | 2 ^ 3 == 0", - "check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z", - "check if [1, 4] != [1, 2]", - "check if hex:12abcd != hex:12ab" + "check if resource($0), operation(\"read\"), right($0, \"read\")" ] } ], @@ -2179,33 +2208,40 @@ "result": { "Ok": 0 }, - "authorizer_code": "allow if true;\n", + "authorizer_code": "resource(\"file1\");\noperation(\"read\");\n\nallow if true;\n", "revocation_ids": [ - "117fa653744c859561555e6a6f5990e3a8e7817f91b87aa6991b6d64297158b4e884c92d10f49f74c96069df722aa676839b72751ca9d1fe83a7025b591de00b" + "628b9a6d74cc80b3ece50befd1f5f0f025c0a35d51708b2e77c11aed5f968b93b4096c87ed8169605716de934e155443f140334d71708fcc4247e5a0a518b30d", + "3046022100b60674854a12814cc36c8aab9600c1d9f9d3160e2334b72c0feede5a56213ea5022100a4f4bbf2dc33b309267af39fce76612017ddb6171e9cd2a3aa8a853f45f1675f" ] } } }, { - "title": "ECDSA secp256r1 signatures", - "filename": "test036_secp256r1.bc", + "title": "ECDSA secp256r1 signature on third-party block", + "filename": "test037_secp256r1_third_party.bc", "token": [ { "symbols": [ "file1", - "file2" + "file2", + "from_third" + ], + "public_keys": [ + "secp256r1/025e918fd4463832aea2823dfd9716a36b4d9b1377bd53dd82ddf4c0bc75ed6bbf" ], - "public_keys": [], "external_key": null, - "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n" + "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\ncheck if from_third(true) trusting secp256r1/025e918fd4463832aea2823dfd9716a36b4d9b1377bd53dd82ddf4c0bc75ed6bbf;\n", + "version": 4 }, { "symbols": [ + "from_third", "0" ], "public_keys": [], - "external_key": null, - "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n" + "external_key": "secp256r1/025e918fd4463832aea2823dfd9716a36b4d9b1377bd53dd82ddf4c0bc75ed6bbf", + "code": "from_third(true);\ncheck if resource($0), operation(\"read\"), right($0, \"read\");\n", + "version": 5 } ], "validations": { @@ -2230,10 +2266,24 @@ "right(\"file1\", \"write\")", "right(\"file2\", \"read\")" ] + }, + { + "origin": [ + 1 + ], + "facts": [ + "from_third(true)" + ] } ], "rules": [], "checks": [ + { + "origin": 0, + "checks": [ + "check if from_third(true) trusting secp256r1/025e918fd4463832aea2823dfd9716a36b4d9b1377bd53dd82ddf4c0bc75ed6bbf" + ] + }, { "origin": 1, "checks": [ @@ -2250,11 +2300,11 @@ }, "authorizer_code": "resource(\"file1\");\noperation(\"read\");\n\nallow if true;\n", "revocation_ids": [ - "760785de30d7348e9c847aab8b3bdad6a0d463f4f50ed9667aade563e9112ee6d2f589630dd7553c2eced2a57edf3636d5c874b35df15120c62fddcbdbd2de09", - "30440220039667c7a4d964e4b449289dc8fd206d7aa0e77eb701a9253b3307d32c177fa8022023f7523c143c5fb55ee4cafe49804702ef05a70883ebf42185b54bd36a7e7cd4" + "70f5402208516fd44cfc9df3dfcfc0a327ee9004f1801ed0a7abdcbbae923d566ddcd2d4a14f4622b35732c4e538af04075cc67ab0888fa2d8923cc668187f0f", + "30450220793f95665d9af646339503a073670ea2c352459d2a2c2e14c57565f6c7eaf6bc022100cccadfc37e46755f52bb054ed206d7335067885df599a69431db40e33f33d4cf" ] } } } ] -} \ No newline at end of file +} diff --git a/src/test/resources/samples/test024_third_party.bc b/src/test/resources/samples/test024_third_party.bc index d2aef528..8b7b8645 100644 Binary files a/src/test/resources/samples/test024_third_party.bc and b/src/test/resources/samples/test024_third_party.bc differ diff --git a/src/test/resources/samples/test026_public_keys_interning.bc b/src/test/resources/samples/test026_public_keys_interning.bc index 392d649c..89a87c7f 100644 Binary files a/src/test/resources/samples/test026_public_keys_interning.bc and b/src/test/resources/samples/test026_public_keys_interning.bc differ diff --git a/src/test/resources/samples/test027_integer_wraparound.bc b/src/test/resources/samples/test027_integer_wraparound.bc index 50aa63b9..463a6c53 100644 Binary files a/src/test/resources/samples/test027_integer_wraparound.bc and b/src/test/resources/samples/test027_integer_wraparound.bc differ diff --git a/src/test/resources/samples/test031_secp256r1.bc b/src/test/resources/samples/test031_secp256r1.bc deleted file mode 100644 index 15a8a429..00000000 Binary files a/src/test/resources/samples/test031_secp256r1.bc and /dev/null differ diff --git a/src/test/resources/samples/test036_secp256r1.bc b/src/test/resources/samples/test036_secp256r1.bc index 15a8a429..8c4c772d 100644 Binary files a/src/test/resources/samples/test036_secp256r1.bc and b/src/test/resources/samples/test036_secp256r1.bc differ diff --git a/src/test/resources/samples/test037_secp256r1_third_party.bc b/src/test/resources/samples/test037_secp256r1_third_party.bc new file mode 100644 index 00000000..d40456e7 Binary files /dev/null and b/src/test/resources/samples/test037_secp256r1_third_party.bc differ