Skip to content

Commit 976b986

Browse files
committed
add a test
1 parent 5895e46 commit 976b986

9 files changed

Lines changed: 84 additions & 28 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public void setEllipticCurve(NanoTDFType.ECCurve curve) {
4444
}
4545
}
4646

47-
public NanoTDFType.ECCurve getEllipticCurveType() {
47+
public NanoTDFType.ECCurve getCurve() {
4848
return NanoTDFType.ECCurve.values()[data.curveMode];
4949
}
5050

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.io.*;
2525
import java.security.*;
2626
import java.security.spec.*;
27+
import java.util.Objects;
2728
// https://www.bouncycastle.org/latest_releases.html
2829

2930
public class ECKeyPair {
@@ -48,7 +49,7 @@ public ECKeyPair() {
4849
}
4950

5051
public ECKeyPair(NanoTDFType.ECCurve curve, ECAlgorithm algorithm) {
51-
this.curve = curve;
52+
this.curve = Objects.requireNonNull(curve);
5253
KeyPairGenerator generator;
5354

5455
try {
@@ -80,6 +81,10 @@ public ECPrivateKey getPrivateKey() {
8081
return (ECPrivateKey) this.keyPair.getPrivate();
8182
}
8283

84+
NanoTDFType.ECCurve getCurve() {
85+
return this.curve;
86+
}
87+
8388
public String publicKeyInPEMFormat() {
8489
StringWriter writer = new StringWriter();
8590
PemWriter pemWriter = new PemWriter(writer);

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public Header(ByteBuffer buffer) {
2626
this.payloadConfig = new SymmetricAndPayloadConfig(buffer.get());
2727
this.policyInfo = new PolicyInfo(buffer, this.eccMode);
2828

29-
int compressedPubKeySize = this.eccMode.getEllipticCurveType().keySize;
29+
int compressedPubKeySize = this.eccMode.getCurve().keySize;
3030
this.ephemeralKey = new byte[compressedPubKeySize];
3131
buffer.get(this.ephemeralKey);
3232
}
@@ -79,10 +79,10 @@ public PolicyInfo getPolicyInfo() {
7979
}
8080

8181
public void setEphemeralKey(byte[] bytes) {
82-
if (bytes.length < eccMode.getEllipticCurveType().keySize) {
82+
if (bytes.length < eccMode.getCurve().keySize) {
8383
throw new IllegalArgumentException("Failed to read ephemeral key - invalid buffer size.");
8484
}
85-
ephemeralKey = Arrays.copyOf(bytes, eccMode.getEllipticCurveType().keySize);
85+
ephemeralKey = Arrays.copyOf(bytes, eccMode.getCurve().keySize);
8686
}
8787

8888
public byte[] getEphemeralKey() {

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

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,20 @@ private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) thro
8282
String url = kasInfo.URL;
8383
if (kasInfo.PublicKey == null || kasInfo.PublicKey.isEmpty()) {
8484
logger.info("no public key provided for KAS at {}, retrieving", url);
85-
kasInfo = services.kas().getECPublicKey(kasInfo, nanoTDFConfig.eccMode.getEllipticCurveType());
85+
kasInfo = services.kas().getECPublicKey(kasInfo, nanoTDFConfig.eccMode.getCurve());
8686
}
8787

8888
// Kas url resource locator
8989
ResourceLocator kasURL = new ResourceLocator(nanoTDFConfig.kasInfoList.get(0).URL, kasInfo.KID);
9090
assert kasURL.getIdentifier() != null : "Identifier in ResourceLocator cannot be null";
9191

92-
ECKeyPair keyPair = new ECKeyPair(nanoTDFConfig.eccMode.getEllipticCurveType(), ECKeyPair.ECAlgorithm.ECDSA);
92+
// it might be better to pull the curve from the OIDC in the PEM but it looks like we
93+
// are just taking the Algorithm as correct
94+
var ecCurve = NanoTDFType.ECCurve.fromAlgorithm(kasInfo.Algorithm);
95+
if (ecCurve != nanoTDFConfig.eccMode.getCurve()) {
96+
logger.warn("ECCurve in NanoTDFConfig [{}] does not match the curve in KASInfo, using KASInfo curve [{}]", nanoTDFConfig.eccMode.getCurve(), ecCurve);
97+
}
98+
ECKeyPair keyPair = new ECKeyPair(ecCurve, ECKeyPair.ECAlgorithm.ECDSA);
9399

94100
// Generate symmetric key
95101
ECPublicKey kasPublicKey = ECKeyPair.publicKeyFromPem(kasInfo.PublicKey);
@@ -138,7 +144,14 @@ private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) thro
138144
// Create header
139145
byte[] compressedPubKey = keyPair.compressECPublickey();
140146
Header header = new Header();
141-
header.setECCMode(nanoTDFConfig.eccMode);
147+
ECCMode mode;
148+
if (nanoTDFConfig.eccMode.getCurve() != keyPair.getCurve()) {
149+
mode = new ECCMode(nanoTDFConfig.eccMode.getECCModeAsByte());
150+
mode.setEllipticCurve(keyPair.getCurve());
151+
} else {
152+
mode = nanoTDFConfig.eccMode;
153+
}
154+
header.setECCMode(mode);
142155
header.setPayloadConfig(nanoTDFConfig.config);
143156
header.setEphemeralKey(compressedPubKey);
144157
header.setKasLocator(kasURL);
@@ -276,7 +289,7 @@ public void readNanoTDF(ByteBuffer nanoTDF, OutputStream outputStream,
276289
}
277290

278291

279-
key = services.kas().unwrapNanoTDF(header.getECCMode().getEllipticCurveType(),
292+
key = services.kas().unwrapNanoTDF(header.getECCMode().getCurve(),
280293
base64HeaderData,
281294
kasUrl);
282295
collectionStore.store(header, new CollectionKey(key));

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

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

3+
import org.slf4j.Logger;
4+
import org.slf4j.LoggerFactory;
5+
6+
import java.util.Arrays;
7+
38
public class NanoTDFType {
9+
private static final Logger log = LoggerFactory.getLogger(NanoTDFType.class);
410
enum ECCurve {
511
SECP256R1("secp256r1", 32, 33, 0x00),
612
SECP384R1("secp384r1", 48, 49, 0x01),
@@ -34,6 +40,20 @@ static ECCurve fromCurveMode(int curveMode) {
3440
}
3541
throw new IllegalArgumentException("No enum constant for curve mode: " + curveMode);
3642
}
43+
44+
public static ECCurve fromAlgorithm(String algorithm) {
45+
if (algorithm == null) {
46+
log.warn("got a null algorithm, returning SECP256R1 as default");
47+
return SECP256R1;
48+
}
49+
50+
assert algorithm.startsWith("ec:");
51+
var searchKey = algorithm.substring("ec:".length());
52+
return Arrays.stream(ECCurve.values())
53+
.filter(v -> v.curveName.equalsIgnoreCase(searchKey))
54+
.findAny()
55+
.orElseThrow(() -> new IllegalArgumentException(String.format("No enum constant for algorithm: %s", algorithm)));
56+
}
3757
}
3858
// ResourceLocator Protocol
3959
public enum Protocol {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public PolicyInfo(ByteBuffer buffer, ECCMode eccMode) {
4747

4848
int bindingBytesSize = 8; // GMAC length
4949
if (this.hasECDSABinding) { // ECDSA - The size of binding depends on the curve.
50-
bindingBytesSize = ECCMode.getECDSASignatureStructSize(eccMode.getEllipticCurveType());
50+
bindingBytesSize = ECCMode.getECDSASignatureStructSize(eccMode.getCurve());
5151
}
5252

5353
this.binding = new byte[bindingBytesSize];

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ void settingAndGettingEphemeralKey() {
4747
ECCMode mode = new ECCMode((byte) 1); // Initialize the ECCMode object
4848
header.setECCMode(mode); // Set the ECCMode object
4949

50-
int keySize = mode.getEllipticCurveType().keySize;
50+
int keySize = mode.getCurve().keySize;
5151
byte[] key = new byte[keySize]; // Ensure the key size is correct
5252
header.setEphemeralKey(key);
5353
assertArrayEquals(key, header.getEphemeralKey());

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ public void testNanoTDFReader()
169169
header2.setPolicyInfo(policyInfo);
170170

171171
int sizeToRead = policyInfo.getTotalSize();
172-
int compressedPubKeySize = header2.getECCMode().getEllipticCurveType().keySize;
172+
int compressedPubKeySize = header2.getECCMode().getCurve().keySize;
173173
byte[] ephemeralKey = new byte[compressedPubKeySize]; // size of compressed public key
174174
System.arraycopy(remainingBytesArray, sizeToRead, ephemeralKey, 0, ephemeralKey.length);
175175
header2.setEphemeralKey(ephemeralKey);
@@ -201,11 +201,11 @@ public void testNanoTDFEncryption()
201201
byte[] tag = new byte[tagSize];
202202

203203
ECCMode eccMode = new ECCMode((byte) 0x0); // no ecdsa binding and 'secp256r1'
204-
ECKeyPair sdkECKeyPair = new ECKeyPair(eccMode.getEllipticCurveType(), ECKeyPair.ECAlgorithm.ECDH);
204+
ECKeyPair sdkECKeyPair = new ECKeyPair(eccMode.getCurve(), ECKeyPair.ECAlgorithm.ECDH);
205205
String sdkPrivateKeyForEncrypt = sdkECKeyPair.privateKeyInPEMFormat();
206206
String sdkPublicKeyForEncrypt = sdkECKeyPair.publicKeyInPEMFormat();
207207

208-
ECKeyPair kasECKeyPair = new ECKeyPair(eccMode.getEllipticCurveType(), ECKeyPair.ECAlgorithm.ECDH);
208+
ECKeyPair kasECKeyPair = new ECKeyPair(eccMode.getCurve(), ECKeyPair.ECAlgorithm.ECDH);
209209
String kasPublicKey = kasECKeyPair.publicKeyInPEMFormat();
210210
// Encrypt
211211
Header header = new Header();

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

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public KASInfo getECPublicKey(Config.KASInfo kasInfo, NanoTDFType.ECCurve curve)
7676
var k2 = kasInfo.clone();
7777
k2.KID = KID;
7878
k2.PublicKey = kasPublicKey;
79+
k2.Algorithm = "ec:secp256r1";
7980
return k2;
8081
}
8182

@@ -98,7 +99,7 @@ public byte[] unwrapNanoTDF(NanoTDFType.ECCurve curve, String header, String kas
9899
Header nTDFHeader = new Header(ByteBuffer.wrap(headerAsBytes));
99100
byte[] ephemeralKey = nTDFHeader.getEphemeralKey();
100101

101-
String publicKeyAsPem = ECKeyPair.publicKeyFromECPoint(ephemeralKey, nTDFHeader.getECCMode().getEllipticCurveType().curveName);
102+
String publicKeyAsPem = ECKeyPair.publicKeyFromECPoint(ephemeralKey, nTDFHeader.getECCMode().getCurve().curveName);
102103

103104
// Generate symmetric key
104105
byte[] symmetricKey = ECKeyPair.computeECDHKey(ECKeyPair.publicKeyFromPem(publicKeyAsPem),
@@ -162,6 +163,7 @@ void encryptionAndDecryptionWithValidKey() throws Exception {
162163

163164
Config.NanoTDFConfig config = Config.newNanoTDFConfig(
164165
Config.withNanoKasInformation(kasInfos.toArray(new Config.KASInfo[0])),
166+
Config.withEllipticCurve("secp384r1"),
165167
Config.witDataAttributes("https://example.com/attr/Classification/value/S",
166168
"https://example.com/attr/Classification/value/X")
167169
);
@@ -201,18 +203,36 @@ void encryptionAndDecryptionWithValidKey() throws Exception {
201203
}
202204
}
203205

204-
void runBasicTest(String kasUrl, boolean allowed, KeyAccessServerRegistryServiceClient kasReg, NanoTDFReaderConfig decryptConfig) throws Exception {
206+
@Test
207+
void testWithDifferentConfigAndKeyValues() throws Exception {
205208
var kasInfos = new ArrayList<>();
206209
var kasInfo = new Config.KASInfo();
207-
kasInfo.URL = kasUrl;
210+
kasInfo.URL = "https://api.example.com/kas";
208211
kasInfo.PublicKey = null;
209212
kasInfos.add(kasInfo);
210-
211-
Config.NanoTDFConfig config = Config.newNanoTDFConfig(
213+
var config = Config.newNanoTDFConfig(
212214
Config.withNanoKasInformation(kasInfos.toArray(new Config.KASInfo[0])),
213-
Config.witDataAttributes("https://example.com/attr/Classification/value/S",
214-
"https://example.com/attr/Classification/value/X")
215+
Config.withEllipticCurve("secp384r1"),
216+
Config.witDataAttributes("https://example.com/attr/Classification/value/S", "https://example.com/attr/Classification/value/X")
215217
);
218+
runBasicTest(null, true, kasRegistryService, null, config);
219+
}
220+
221+
void runBasicTest(String kasUrl, boolean allowed, KeyAccessServerRegistryServiceClient kasReg, NanoTDFReaderConfig decryptConfig, Config.NanoTDFConfig writerConfig) throws Exception {
222+
Config.NanoTDFConfig config;
223+
if (writerConfig == null) {
224+
var kasInfos = new ArrayList<>();
225+
var kasInfo = new Config.KASInfo();
226+
kasInfo.URL = kasUrl;
227+
kasInfo.PublicKey = null;
228+
kasInfos.add(kasInfo);
229+
config = Config.newNanoTDFConfig(
230+
Config.withNanoKasInformation(kasInfos.toArray(new Config.KASInfo[0])),
231+
Config.witDataAttributes("https://example.com/attr/Classification/value/S", "https://example.com/attr/Classification/value/X")
232+
);
233+
} else {
234+
config = writerConfig;
235+
}
216236

217237
String plainText = "Virtru!!";
218238
ByteBuffer byteBuffer = ByteBuffer.wrap(plainText.getBytes());
@@ -244,8 +264,6 @@ void runBasicTest(String kasUrl, boolean allowed, KeyAccessServerRegistryService
244264
assertThat(e.getMessage()).contains("KasAllowlist");
245265
}
246266
}
247-
248-
249267
}
250268

251269
@Test
@@ -265,18 +283,18 @@ void kasAllowlistTests() throws Exception {
265283
"https://localhost:8080/kas"
266284
);
267285
for (String kasUrl : kasUrlsSuccess) {
268-
runBasicTest(kasUrl, true, kasRegistryService, null);
286+
runBasicTest(kasUrl, true, kasRegistryService, null, null);
269287
}
270288
for (String kasUrl : kasUrlsFail) {
271-
runBasicTest(kasUrl, false, kasRegistryService, null);
289+
runBasicTest(kasUrl, false, kasRegistryService, null, null);
272290
}
273291

274292
// test with kasAllowlist
275-
runBasicTest("http://api.example.com/kas", true, null, Config.newNanoTDFReaderConfig(Config.WithNanoKasAllowlist("http://api.example.com/kas")));
276-
runBasicTest(platformUrl+"/kas", false, null, Config.newNanoTDFReaderConfig(Config.WithNanoKasAllowlist("http://api.example.com/kas")));
293+
runBasicTest("http://api.example.com/kas", true, null, Config.newNanoTDFReaderConfig(Config.WithNanoKasAllowlist("http://api.example.com/kas")), null);
294+
runBasicTest(platformUrl+"/kas", false, null, Config.newNanoTDFReaderConfig(Config.WithNanoKasAllowlist("http://api.example.com/kas")), null);
277295

278296
// test ignore kasAllowlist
279-
runBasicTest(platformUrl+"/kas", true, null, Config.newNanoTDFReaderConfig(Config.WithNanoKasAllowlist("http://api.example.com/kas"), Config.WithNanoIgnoreKasAllowlist(true)));
297+
runBasicTest(platformUrl+"/kas", true, null, Config.newNanoTDFReaderConfig(Config.WithNanoKasAllowlist("http://api.example.com/kas"), Config.WithNanoIgnoreKasAllowlist(true)), null);
280298
}
281299

282300
@Test

0 commit comments

Comments
 (0)