Skip to content

Commit 50001fd

Browse files
committed
fix(sdk): parse the component sizes
1 parent 6ff003c commit 50001fd

File tree

3 files changed

+80
-8
lines changed

3 files changed

+80
-8
lines changed

sdk/src/main/java/io/opentdf/platform/sdk/PolicyInfo.java

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import java.nio.ByteBuffer;
44

55
public class PolicyInfo {
6+
private static final int DEFAULT_BINDING_SIZE = 8;
67
private NanoTDFType.PolicyType type;
7-
private boolean hasECDSABinding;
88
private byte[] body;
99
private byte[] binding;
1010

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

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

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

@@ -45,13 +44,39 @@ public PolicyInfo(ByteBuffer buffer, ECCMode eccMode) {
4544
}
4645
}
4746

48-
int bindingBytesSize = 8; // GMAC length
49-
if (this.hasECDSABinding) { // ECDSA - The size of binding depends on the curve.
50-
bindingBytesSize = ECCMode.getECDSASignatureStructSize(eccMode.getCurve());
47+
this.binding = readBinding(buffer, eccMode);
48+
}
49+
50+
static byte[] readBinding(ByteBuffer buffer, ECCMode eccMode) {
51+
byte[] binding;
52+
if (eccMode.isECDSABindingEnabled()) { // ECDSA - The size of binding depends on the curve.
53+
int rSize = getSize(buffer.get(), eccMode.getCurve());
54+
// don't bother to validate since we can only create an array of size 1024 bytes
55+
byte[] rBytes = new byte[rSize];
56+
buffer.get(rBytes);
57+
int sSize = getSize(buffer.get(), eccMode.getCurve());
58+
byte[] sBytes = new byte[sSize];
59+
buffer.get(sBytes);
60+
int bindingByteSize = eccMode.getCurve().getKeySize();
61+
binding = new byte[2 * bindingByteSize];
62+
System.arraycopy(rBytes, 0, binding, bindingByteSize - rSize, rSize);
63+
System.arraycopy(sBytes, 0, binding, bindingByteSize + bindingByteSize - sSize, sSize);
64+
} else {
65+
binding = new byte[DEFAULT_BINDING_SIZE];
66+
buffer.get(binding);
5167
}
5268

53-
this.binding = new byte[bindingBytesSize];
54-
buffer.get(this.binding);
69+
return binding;
70+
}
71+
72+
private static int getSize(byte size, NanoTDFType.ECCurve curve) {
73+
int elementSize = Byte.toUnsignedInt(size);
74+
if (elementSize > curve.getKeySize()) {
75+
throw new SDK.MalformedTDFException(
76+
String.format("Invalid ECDSA binding size. Expected signature components to be at most %d bytes but got (%d) bytes for curve %s.",
77+
curve.getKeySize(), elementSize, curve.getCurveName()));
78+
}
79+
return elementSize;
5580
}
5681

5782
public int getTotalSize() {
@@ -64,7 +89,6 @@ public int getTotalSize() {
6489
if (type == NanoTDFType.PolicyType.EMBEDDED_POLICY_PLAIN_TEXT ||
6590
type == NanoTDFType.PolicyType.EMBEDDED_POLICY_ENCRYPTED) {
6691

67-
int policySize = body.length;
6892
totalSize = (1 + Short.BYTES + body.length + binding.length);
6993
} else {
7094
throw new RuntimeException("Embedded policy with key access is not supported.");

sdk/src/main/java/io/opentdf/platform/sdk/SDK.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,15 @@ public String getPlatformUrl() {
176176
return platformUrl;
177177
}
178178

179+
/**
180+
* {@link MalformedTDFException} indicates that the TDF is malformed in some way
181+
*/
182+
public static class MalformedTDFException extends SDKException {
183+
public MalformedTDFException(String errorMessage) {
184+
super(errorMessage);
185+
}
186+
}
187+
179188
/**
180189
* {@link SplitKeyException} is thrown when the SDK encounters an error related to
181190
* the inability to reconstruct a split key during decryption.

sdk/src/test/java/io/opentdf/platform/sdk/PolicyInfoTest.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
package io.opentdf.platform.sdk;
22

3+
import org.bouncycastle.asn1.ASN1Integer;
4+
import org.bouncycastle.asn1.DERBitString;
35
import org.junit.jupiter.api.BeforeEach;
46
import org.junit.jupiter.api.Test;
7+
8+
import java.io.ByteArrayOutputStream;
9+
import java.io.IOException;
10+
import java.math.BigInteger;
11+
import java.nio.ByteBuffer;
12+
13+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
514
import static org.junit.jupiter.api.Assertions.*;
615

716
class PolicyInfoTest {
@@ -58,4 +67,34 @@ void settingAndGettingPolicyBinding() {
5867
policyInfo.setPolicyBinding(binding);
5968
assertArrayEquals(binding, policyInfo.getPolicyBinding());
6069
}
70+
71+
@Test
72+
void testReadingDEREncodedSignature() throws IOException {
73+
var curve = NanoTDFType.ECCurve.SECP384R1;
74+
ByteBuffer buffer = ByteBuffer.allocate(1024);
75+
buffer.put((byte)2);
76+
buffer.put(new BigInteger("200", 10).toByteArray());
77+
buffer.put((byte)3);
78+
buffer.put(new BigInteger("65536", 10).toByteArray());
79+
80+
81+
ECCMode eccMode = new ECCMode();
82+
eccMode.setECDSABinding(true);
83+
eccMode.setEllipticCurve(curve);
84+
85+
buffer.flip();
86+
87+
byte[] signature = PolicyInfo.readBinding(buffer, eccMode);
88+
assertThat(signature).hasSize(2 * curve.getKeySize());
89+
90+
var rBytes = new byte[curve.getKeySize()];
91+
System.arraycopy(signature, 0, rBytes, 0, rBytes.length);
92+
var r = new BigInteger(1, rBytes);
93+
assertThat(r).isEqualTo(new BigInteger("200", 10));
94+
95+
var sBytes = new byte[curve.getKeySize()];
96+
System.arraycopy(signature, curve.getKeySize(), sBytes, 0, curve.getKeySize());
97+
var s = new BigInteger(1, sBytes);
98+
assertThat(s).isEqualTo(new BigInteger("65536", 10));
99+
}
61100
}

0 commit comments

Comments
 (0)