Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix pubkey interning test #104

Merged
merged 16 commits into from
Jun 23, 2024
Prev Previous commit
Next Next commit
move the 3rd party methods to UnverifiedBiscuit
  • Loading branch information
Geal committed Jun 20, 2024
commit e911a75c4cabd7140257a557d3675ebf17387a95
91 changes: 3 additions & 88 deletions src/main/java/org/biscuitsec/biscuit/token/Biscuit.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
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.datalog.SymbolTable;
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.control.Either;
import io.vavr.control.Option;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.*;
import java.util.*;

@@ -364,95 +359,15 @@ public Biscuit attenuate(final SecureRandom rng, final KeyPair keypair, Block bl
return new Biscuit(copiedBiscuit.authority, blocks, symbols, container, publicKeyToBlockId, revocation_ids);
}

/**
* Generates a third party block request from a token
*/
public ThirdPartyBlockRequest thirdPartyRequest() {
PublicKey previousKey;
if(this.serializedBiscuit.blocks.isEmpty()) {
previousKey = this.serializedBiscuit.authority.key;
} else {
previousKey = this.serializedBiscuit.blocks.get(this.serializedBiscuit.blocks.size() - 1).key;
}

List<PublicKey> publicKeys = new ArrayList<>(this.symbols.publicKeys());
return new ThirdPartyBlockRequest(previousKey, publicKeys);
}

/**
* Generates a third party block request from a token
*/
public Biscuit appendThirdPartyBlock(PublicKey externalKey, ThirdPartyBlockContents blockResponse)
throws NoSuchAlgorithmException, SignatureException, InvalidKeyException, Error {
KeyPair nextKeyPair = new KeyPair();

Signature sgr = new EdDSAEngine(MessageDigest.getInstance(org.biscuitsec.biscuit.crypto.KeyPair.ed25519.getHashAlgorithm()));
sgr.initVerify(externalKey.key);

sgr.update(blockResponse.payload);
ByteBuffer algo_buf = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN);
algo_buf.putInt(Integer.valueOf(Schema.PublicKey.Algorithm.Ed25519.getNumber()));
algo_buf.flip();
sgr.update(algo_buf);

PublicKey previousKey;
if(this.serializedBiscuit.blocks.isEmpty()) {
previousKey = this.serializedBiscuit.authority.key;
} else {
previousKey = this.serializedBiscuit.blocks.get(this.serializedBiscuit.blocks.size() - 1).key;
}
sgr.update(previousKey.toBytes());
if (!sgr.verify(blockResponse.signature)) {
throw new Error.FormatError.Signature.InvalidSignature("signature error: Verification equation was not satisfied");
}

Either<Error.FormatError, Block> res = Block.from_bytes(blockResponse.payload, Option.some(externalKey));
if(res.isLeft()) {
throw res.getLeft();
}

Block block = res.get();

ExternalSignature externalSignature = new ExternalSignature(externalKey, blockResponse.signature);

Biscuit copiedBiscuit = this.copy();

Either<Error.FormatError, SerializedBiscuit> containerRes = copiedBiscuit.serializedBiscuit.append(nextKeyPair, block, Option.some(externalSignature));
if (containerRes.isLeft()) {
throw containerRes.getLeft();
}
UnverifiedBiscuit b = super.appendThirdPartyBlock(externalKey, blockResponse);

SerializedBiscuit container = containerRes.get();

SymbolTable symbols = new SymbolTable(copiedBiscuit.symbols);

ArrayList<Block> blocks = new ArrayList<>();
for (Block b : copiedBiscuit.blocks) {
blocks.add(b);
}
blocks.add(block);

for(PublicKey pk: block.publicKeys) {
symbols.insert(pk);
}

long pkIndex = symbols.insert(externalKey);
// if (copiedBiscuit.publicKeyToBlockId.


HashMap<Long, List<Long>> publicKeyToBlockId = new HashMap<>();
publicKeyToBlockId.putAll(this.publicKeyToBlockId);
if(publicKeyToBlockId.containsKey(pkIndex)) {
publicKeyToBlockId.get(pkIndex).add((long)this.blocks.size()+1);
} else {
List<Long> list = new ArrayList<>();
list.add((long)this.blocks.size()+1);
publicKeyToBlockId.put(pkIndex, list);
}

List<byte[]> revocation_ids = container.revocation_identifiers();

return new Biscuit(copiedBiscuit.authority, blocks, symbols, container, publicKeyToBlockId, revocation_ids);
// no need to verify again, we are already working from a verified token
return Biscuit.from_serialized_biscuit(b.serializedBiscuit, b.symbols);
}

/**
101 changes: 97 additions & 4 deletions src/main/java/org/biscuitsec/biscuit/token/UnverifiedBiscuit.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
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.control.Either;
import io.vavr.control.Option;
import org.biscuitsec.biscuit.datalog.Check;
import org.biscuitsec.biscuit.datalog.SymbolTable;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.SignatureException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.*;
import java.util.*;
import java.util.stream.Collectors;

@@ -232,6 +234,97 @@ public Option<Integer> root_key_id() {
return this.root_key_id;
}

/**
* Generates a third party block request from a token
*/
public ThirdPartyBlockRequest thirdPartyRequest() {
PublicKey previousKey;
if(this.serializedBiscuit.blocks.isEmpty()) {
previousKey = this.serializedBiscuit.authority.key;
} else {
previousKey = this.serializedBiscuit.blocks.get(this.serializedBiscuit.blocks.size() - 1).key;
}

List<PublicKey> publicKeys = new ArrayList<>(this.symbols.publicKeys());
return new ThirdPartyBlockRequest(previousKey, publicKeys);
}


/**
* Generates a third party block request from a token
*/
public UnverifiedBiscuit appendThirdPartyBlock(PublicKey externalKey, ThirdPartyBlockContents blockResponse)
throws NoSuchAlgorithmException, SignatureException, InvalidKeyException, Error {
KeyPair nextKeyPair = new KeyPair();

Signature sgr = new EdDSAEngine(MessageDigest.getInstance(org.biscuitsec.biscuit.crypto.KeyPair.ed25519.getHashAlgorithm()));
sgr.initVerify(externalKey.key);

sgr.update(blockResponse.payload);
ByteBuffer algo_buf = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this serialization logic might be better encapsulated in a method rather than inlined here (and i assume in other places)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

something to look at after the ECDSA PR has merged, I think, otherwise we'll get lots of conflicts

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried abstract this into a function for my remote_signer branch however these new third party tests are the only ones which are failing when trying to rebase my branch. Still digging into it, not sure whether subtle nuance or not.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think I see my issue, around the externalSignature which appears to be specific to third party.

algo_buf.putInt(Integer.valueOf(Schema.PublicKey.Algorithm.Ed25519.getNumber()));
algo_buf.flip();
sgr.update(algo_buf);

PublicKey previousKey;
if(this.serializedBiscuit.blocks.isEmpty()) {
previousKey = this.serializedBiscuit.authority.key;
} else {
previousKey = this.serializedBiscuit.blocks.get(this.serializedBiscuit.blocks.size() - 1).key;
}
sgr.update(previousKey.toBytes());
if (!sgr.verify(blockResponse.signature)) {
throw new Error.FormatError.Signature.InvalidSignature("signature error: Verification equation was not satisfied");
}

Either<Error.FormatError, Block> res = Block.from_bytes(blockResponse.payload, Option.some(externalKey));
if(res.isLeft()) {
throw res.getLeft();
}

Block block = res.get();

ExternalSignature externalSignature = new ExternalSignature(externalKey, blockResponse.signature);

UnverifiedBiscuit copiedBiscuit = this.copy();

Either<Error.FormatError, SerializedBiscuit> containerRes = copiedBiscuit.serializedBiscuit.append(nextKeyPair, block, Option.some(externalSignature));
if (containerRes.isLeft()) {
throw containerRes.getLeft();
}

SerializedBiscuit container = containerRes.get();

SymbolTable symbols = new SymbolTable(copiedBiscuit.symbols);

ArrayList<Block> blocks = new ArrayList<>();
for (Block b : copiedBiscuit.blocks) {
blocks.add(b);
}
blocks.add(block);

for(PublicKey pk: block.publicKeys) {
symbols.insert(pk);
}

long pkIndex = symbols.insert(externalKey);
// if (copiedBiscuit.publicKeyToBlockId.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be removed i assume



HashMap<Long, List<Long>> publicKeyToBlockId = new HashMap<>();
publicKeyToBlockId.putAll(this.publicKeyToBlockId);
if(publicKeyToBlockId.containsKey(pkIndex)) {
publicKeyToBlockId.get(pkIndex).add((long)this.blocks.size()+1);
} else {
List<Long> list = new ArrayList<>();
list.add((long)this.blocks.size()+1);
publicKeyToBlockId.put(pkIndex, list);
}

List<byte[]> revocation_ids = container.revocation_identifiers();

return new UnverifiedBiscuit(copiedBiscuit.authority, blocks, symbols, container, publicKeyToBlockId, revocation_ids);
}

/**
* Prints a token's content