Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions biscuit-core/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!--
~ Copyright (c) 2019 Geoffroy Couprie <contact@geoffroycouprie.com> and Contributors to the Eclipse Foundation.
~ SPDX-License-Identifier: Apache-2.0
-->

<project>
<modelVersion>4.0.0</modelVersion>
<artifactId>biscuit-core</artifactId>
<packaging>jar</packaging>

<parent>
<groupId>org.eclipse</groupId>
<artifactId>biscuit-java</artifactId>
<version>4.1.0</version>
</parent>

<dependencies>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>${protobuf.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
</project>
56 changes: 56 additions & 0 deletions biscuit-core/src/main/java/org/eclipse/biscuit/crypto/KeyPair.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2019 Geoffroy Couprie <contact@geoffroycouprie.com> and Contributors to the Eclipse Foundation.
* SPDX-License-Identifier: Apache-2.0
*/

package org.eclipse.biscuit.crypto;

import biscuit.format.schema.Schema.PublicKey.Algorithm;
import java.security.SecureRandom;
import java.util.ServiceLoader;
import java.util.stream.Collectors;
import org.eclipse.biscuit.error.Error;
import org.eclipse.biscuit.token.builder.Utils;

/** Private and public key. */
public abstract class KeyPair implements Signer {
public interface Factory {
KeyPair generate(Algorithm algorithm, byte[] bytes) throws Error.FormatError;

KeyPair generate(Algorithm algorithm, SecureRandom rng) throws Error.FormatError;
}

private static final Factory factory;

static {
var factories = ServiceLoader.load(KeyPair.Factory.class).stream().collect(Collectors.toList());
if (factories.size() != 1) {
throw new IllegalStateException(
"A single KeyPair implementation expected; found " + factories.size());
}
factory = factories.get(0).get();
}

public static KeyPair generate(Algorithm algorithm) throws Error.FormatError {
return generate(algorithm, new SecureRandom());
}

public static KeyPair generate(Algorithm algorithm, String hex) throws Error.FormatError {
return generate(algorithm, Utils.hexStringToByteArray(hex));
}

public static KeyPair generate(Algorithm algorithm, byte[] bytes) throws Error.FormatError {
return factory.generate(algorithm, bytes);
}

public static KeyPair generate(Algorithm algorithm, SecureRandom rng) throws Error.FormatError {
return factory.generate(algorithm, rng);
}

public abstract byte[] toBytes();

public abstract String toHex();

@Override
public abstract PublicKey getPublicKey();
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,34 @@
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.biscuit.error.Error;
import org.eclipse.biscuit.token.builder.Utils;

public abstract class PublicKey {
public interface Factory {
PublicKey load(byte[] bytes) throws Error.FormatError.InvalidKey;
PublicKey load(Algorithm algorithm, byte[] bytes) throws Error.FormatError;
}

public static final Factory DEFAULT_ED25519_FACTORY =
bytes -> Ed25519PublicKey.loadEd25519(bytes);
public static final Factory DEFAULT_SECP256R1_FACTORY =
bytes -> SECP256R1PublicKey.loadSECP256R1(bytes);
private static final Factory factory;

private static volatile Factory ed25519Factory = DEFAULT_ED25519_FACTORY;
private static volatile Factory secp256r1Factory = DEFAULT_SECP256R1_FACTORY;
static {
var factories =
ServiceLoader.load(PublicKey.Factory.class).stream().collect(Collectors.toList());
if (factories.size() != 1) {
throw new IllegalStateException(
"A single PublicKey implementation expected; found " + factories.size());
}
factory = factories.get(0).get();
}

private static final Set<Algorithm> SUPPORTED_ALGORITHMS =
Set.of(Algorithm.Ed25519, Algorithm.SECP256R1);

public static PublicKey load(Algorithm algorithm, byte[] data) throws Error.FormatError {
if (algorithm == Algorithm.Ed25519) {
return ed25519Factory.load(data);
} else if (algorithm == Algorithm.SECP256R1) {
return secp256r1Factory.load(data);
} else {
throw new IllegalArgumentException("Unsupported algorithm");
}
return factory.load(algorithm, data);
}

public static PublicKey load(Algorithm algorithm, String hex) throws Error.FormatError {
Expand All @@ -66,34 +66,8 @@ public static PublicKey deserialize(Schema.PublicKey pk) throws Error.FormatErro
return PublicKey.load(pk.getAlgorithm(), pk.getKey().toByteArray());
}

public static Optional<Error> validateSignatureLength(Algorithm algorithm, int length) {
Optional<Error> error = Optional.empty();
if (algorithm == Algorithm.Ed25519) {
if (length != Ed25519KeyPair.SIGNATURE_LENGTH) {
error = Optional.of(new Error.FormatError.Signature.InvalidSignatureSize(length));
}
} else if (algorithm == Algorithm.SECP256R1) {
if (length < SECP256R1KeyPair.MINIMUM_SIGNATURE_LENGTH
|| length > SECP256R1KeyPair.MAXIMUM_SIGNATURE_LENGTH) {
error = Optional.of(new Error.FormatError.Signature.InvalidSignatureSize(length));
}
} else {
error =
Optional.of(new Error.FormatError.Signature.InvalidSignature("unsupported algorithm"));
}
return error;
}

public static void setEd25519Factory(Factory factory) {
ed25519Factory = factory;
}

public static void setSECP256R1Factory(Factory factory) {
secp256r1Factory = factory;
}

public abstract Algorithm getAlgorithm();

public abstract boolean verify(byte[] data, byte[] signature)
public abstract Optional<Error> verify(byte[] data, byte[] signature)
throws InvalidKeyException, SignatureException, NoSuchAlgorithmException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,12 @@ public Result<Void, Error> verify(PublicKey root)

byte[] payload =
BlockSignatureBuffer.generateBlockSignaturePayloadV0(block, nextKey, Optional.empty());
if (currentKey.verify(payload, signature)) {
currentKey = nextKey;
} else {
return Result.err(
new Error.FormatError.Signature.InvalidSignature(
"signature error: Verification equation was not satisfied"));
var verificationResult = currentKey.verify(payload, signature);
if (verificationResult.isPresent()) {
return Result.err(verificationResult.get());
}

currentKey = nextKey;
}

if (this.next.getPublicKey().equals(currentKey)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
package org.eclipse.biscuit.datalog.expressions;

import biscuit.format.schema.Schema;
import com.google.re2j.Matcher;
import com.google.re2j.Pattern;
import java.io.UnsupportedEncodingException;
import java.util.ArrayDeque;
import java.util.ArrayList;
Expand All @@ -24,6 +22,7 @@
import org.eclipse.biscuit.datalog.Term;
import org.eclipse.biscuit.error.Error;
import org.eclipse.biscuit.error.Result;
import org.eclipse.biscuit.regex.PatternMatcher;
import org.eclipse.biscuit.token.builder.Expression;

public abstract class Op {
Expand Down Expand Up @@ -455,9 +454,7 @@ public void evaluate(
"cannot find string in symbols for index " + ((Term.Str) right).value());
}

Pattern p = Pattern.compile(rightS.get());
Matcher m = p.matcher(leftS.get());
stack.push(new Term.Bool(m.find()));
stack.push(new Term.Bool(PatternMatcher.create(rightS.get()).match(leftS.get())));
}
break;
case Add:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.eclipse.biscuit.datalog.expressions.Expression;

public abstract class Error extends Exception {
Expand Down Expand Up @@ -265,6 +267,46 @@ public JsonNode toJson() {
}
}

public static final class BlockSignatureDeserializationError extends FormatError {
private final String err;

public BlockSignatureDeserializationError(byte[] signature) {
this.err =
"block signature deserialization error: "
+ IntStream.range(0, signature.length)
.mapToObj(i -> String.valueOf(signature[i] & 0xff))
.collect(Collectors.joining(", ", "[", "]"));
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
BlockSignatureDeserializationError other = (BlockSignatureDeserializationError) o;
return err.equals(other.err);
}

@Override
public int hashCode() {
return Objects.hash(err);
}

@Override
public String toString() {
return "Err(FormatError.BlockSignatureDeserializationError{ error: " + err + " }";
}

@Override
public JsonNode toJson() {
return FormatError.jsonWrapper(
objectMapper.createObjectNode().put("BlockSignatureDeserializationError", this.err));
}
}

public static final class BlockSerializationError extends FormatError {
private final String err;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.eclipse.biscuit.regex;

import java.util.ServiceLoader;
import java.util.stream.Collectors;

public abstract class PatternMatcher {
public interface Factory {
PatternMatcher create(String regex);
}

private static final Factory factory;

static {
var factories =
ServiceLoader.load(PatternMatcher.Factory.class).stream().collect(Collectors.toList());
if (factories.size() != 1) {
throw new IllegalStateException(
"A single PatternMatcher implementation expected; found " + factories.size());
}
factory = factories.get(0).get();
}

public static PatternMatcher create(String regex) {
return factory.create(regex);
}

public abstract boolean match(CharSequence input);
}
Original file line number Diff line number Diff line change
Expand Up @@ -291,9 +291,9 @@ public UnverifiedBiscuit appendThirdPartyBlock(
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");
var verificationResult = externalKey.verify(payload, blockResponse.getSignature());
if (verificationResult.isPresent()) {
throw verificationResult.get();
}

var res = Block.fromBytes(blockResponse.getPayload(), Optional.of(externalKey));
Expand Down
Loading