Skip to content
Merged
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
6 changes: 0 additions & 6 deletions sdk/src/main/java/io/opentdf/platform/sdk/ECCMode.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,12 +55,6 @@ public byte getECCModeAsByte() {
return (byte) value;
}

public static int getECDSASignatureStructSize(NanoTDFType.ECCurve curve) {
int keySize = curve.getKeySize();
return (1 + keySize + 1 + keySize);
}


@Nonnull
public NanoTDFType.ECCurve getCurve() {
return NanoTDFType.ECCurve.fromCurveMode(data.curveMode);
Expand Down
41 changes: 33 additions & 8 deletions sdk/src/main/java/io/opentdf/platform/sdk/PolicyInfo.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,8 +3,8 @@
import java.nio.ByteBuffer;

public class PolicyInfo {
private static final int DEFAULT_BINDING_SIZE = 8;
private NanoTDFType.PolicyType type;
private boolean hasECDSABinding;
private byte[] body;
private byte[] binding;

Expand All@@ -13,7 +13,6 @@ public PolicyInfo() {

public PolicyInfo(ByteBuffer buffer, ECCMode eccMode) {
this.type = NanoTDFType.PolicyType.values()[buffer.get()];
this.hasECDSABinding = eccMode.isECDSABindingEnabled();

if (this.type == NanoTDFType.PolicyType.REMOTE_POLICY) {

Expand DownExpand Up@@ -45,13 +44,40 @@ public PolicyInfo(ByteBuffer buffer, ECCMode eccMode) {
}
}

int bindingBytesSize = 8; // GMAC length
if (this.hasECDSABinding) { // ECDSA - The size of binding depends on the curve.
bindingBytesSize = ECCMode.getECDSASignatureStructSize(eccMode.getCurve());
this.binding = readBinding(buffer, eccMode);
}

static byte[] readBinding(ByteBuffer buffer, ECCMode eccMode) {
byte[] binding;
if (eccMode.isECDSABindingEnabled()) { // ECDSA - The size of binding depends on the curve.
int rSize = getSize(buffer.get(), eccMode.getCurve());
byte[] rBytes = new byte[rSize];
buffer.get(rBytes);
int sSize = getSize(buffer.get(), eccMode.getCurve());
byte[] sBytes = new byte[sSize];
buffer.get(sBytes);
binding = ByteBuffer.allocate(rSize + sSize + 2)
.put((byte) rSize)
.put(rBytes)
.put((byte) sSize)
.put(sBytes)
.array();
} else {
binding = new byte[DEFAULT_BINDING_SIZE];
buffer.get(binding);
}

this.binding = new byte[bindingBytesSize];
buffer.get(this.binding);
return binding;
}

private static int getSize(byte size, NanoTDFType.ECCurve curve) {
int elementSize = Byte.toUnsignedInt(size);
if (elementSize > curve.getKeySize()) {
throw new SDK.MalformedTDFException(
String.format("Invalid ECDSA binding size. Expected signature components to be at most %d bytes but got (%d) bytes for curve %s.",
curve.getKeySize(), elementSize, curve.getCurveName()));
}
return elementSize;
}

public int getTotalSize() {
Expand All@@ -64,7 +90,6 @@ public int getTotalSize() {
if (type == NanoTDFType.PolicyType.EMBEDDED_POLICY_PLAIN_TEXT ||
type == NanoTDFType.PolicyType.EMBEDDED_POLICY_ENCRYPTED) {

int policySize = body.length;
totalSize = (1 + Short.BYTES + body.length + binding.length);
} else {
throw new RuntimeException("Embedded policy with key access is not supported.");
Expand Down
11 changes: 10 additions & 1 deletion sdk/src/main/java/io/opentdf/platform/sdk/SDK.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -166,7 +166,7 @@ public static Manifest readManifest(SeekableByteChannel tdfBytes) throws SDKExce
* to get the {@link Manifest} from a TDF.
* @param manifest The {@link Manifest} containing the policy.
* @return The decoded {@link PolicyObject}.
* @throws SDKException if there is an error during decoding.
* @throws {@link SDKException} if there is an error during decoding.
*/
public static PolicyObject decodePolicyObject(Manifest manifest) throws SDKException {
return Manifest.decodePolicyObject(manifest);
Expand All@@ -176,6 +176,15 @@ public String getPlatformUrl() {
return platformUrl;
}

/**
* Indicates that the TDF is malformed in some way
*/
public static class MalformedTDFException extends SDKException {
public MalformedTDFException(String errorMessage) {
super(errorMessage);
}
}

/**
* {@link SplitKeyException} is thrown when the SDK encounters an error related to
* the inability to reconstruct a split key during decryption.
Expand Down
81 changes: 81 additions & 0 deletions sdk/src/test/java/io/opentdf/platform/sdk/PolicyInfoTest.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,13 @@

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Random;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.jupiter.api.Assertions.*;

class PolicyInfoTest {
Expand DownExpand Up@@ -58,4 +65,78 @@ void settingAndGettingPolicyBinding() {
policyInfo.setPolicyBinding(binding);
assertArrayEquals(binding, policyInfo.getPolicyBinding());
}


BigInteger getRandomBigInteger(Random rand, int byteLength) {
return new BigInteger((1+rand.nextInt(byteLength-1))*8, rand);
}

@Test
void testReadingSignatureWithComponentSizes() {
var rand = new Random();
var curve = NanoTDFType.ECCurve.SECP256R1;
for (var i = 0; i < 100; i++) {
var rBytes = getRandomBigInteger(rand, curve.getKeySize()).toByteArray();
var sBytes = getRandomBigInteger(rand, curve.getKeySize()) .toByteArray();
var buffer = ByteBuffer.allocate(rBytes.length + sBytes.length + 2);
buffer.put((byte)rBytes.length);
buffer.put(rBytes);
buffer.put((byte) sBytes.length);
buffer.put(sBytes);

var originalSig = Arrays.copyOf(buffer.array(), buffer.position());

buffer.flip();

ECCMode eccMode = new ECCMode();
eccMode.setECDSABinding(true);
eccMode.setEllipticCurve(curve);

byte[] signature = PolicyInfo.readBinding(buffer, eccMode);
assertThat(signature).containsExactly(originalSig);
// make sure we read all bytes so that reading continues after us in the TDF
assertThat(buffer.position()).isEqualTo(buffer.capacity());
}
}

@Test
void testParsingTooBigSignatureComponents() {
{
var rand = new Random();
var curve = NanoTDFType.ECCurve.SECP256R1;
var rBytes = new BigInteger((curve.getKeySize() + 1) * 8, rand).toByteArray();
var sBytes = getRandomBigInteger(rand, curve.getKeySize()).toByteArray();
var buffer = ByteBuffer.allocate(rBytes.length + sBytes.length + 2);
buffer.put((byte) rBytes.length);
buffer.put(rBytes);
buffer.put((byte) sBytes.length);
buffer.put(sBytes);

buffer.flip();

ECCMode eccMode = new ECCMode();
eccMode.setECDSABinding(true);
eccMode.setEllipticCurve(curve);
assertThrows(SDK.MalformedTDFException.class, () -> PolicyInfo.readBinding(buffer, eccMode));
}

{
var rand = new Random();
var curve = NanoTDFType.ECCurve.SECP256R1;
var rBytes = getRandomBigInteger(rand, curve.getKeySize()).toByteArray();
var sBytes = new BigInteger((curve.getKeySize() + 1) * 8, rand).toByteArray();
var buffer = ByteBuffer.allocate(rBytes.length + sBytes.length + 2);
buffer.put((byte) rBytes.length);
buffer.put(rBytes);
buffer.put((byte) sBytes.length);
buffer.put(sBytes);

buffer.flip();

ECCMode eccMode = new ECCMode();
eccMode.setECDSABinding(true);
eccMode.setEllipticCurve(curve);
assertThrows(SDK.MalformedTDFException.class, () -> PolicyInfo.readBinding(buffer, eccMode));
}
}
Comment thread
mkleene marked this conversation as resolved.
}
Loading