certStreams = new ArrayList<>(certFiles.length);
- for (File certFile : certFiles) {
- certStreams.add(new FileInputStream(certFile));
- }
- X509ExtendedTrustManager trustManager = PemUtils.loadTrustMaterial(certStreams.toArray(new InputStream[0]));
- this.sslFactory = SSLFactory.builder().withDefaultTrustMaterial().withSystemTrustMaterial()
- .withTrustMaterial(trustManager).build();
+ logger.info("Loading certificates from: {}", certsDirPath);
+ TrustProvider provider = TrustProvider.fromDirectory(certsDirPath);
+ this.sslSocketFactory = provider.getSslSocketFactory();
+ this.trustManager = provider.getTrustManager();
return this;
}
/**
* Add SSL Context with default system trust material + certs contained in a
* Java keystore
- *
+ *
* @param keystorePath Path to keystore
* @param keystorePassword Password to keystore
*/
public SDKBuilder sslFactoryFromKeyStore(String keystorePath, String keystorePassword) {
- this.sslFactory = SSLFactory.builder().withDefaultTrustMaterial().withSystemTrustMaterial()
- .withTrustMaterial(Path.of(keystorePath),
- keystorePassword == null ? "".toCharArray() : keystorePassword.toCharArray())
- .build();
+ try {
+ TrustProvider provider = TrustProvider.fromKeyStore(
+ Path.of(keystorePath),
+ keystorePassword == null ? "".toCharArray() : keystorePassword.toCharArray());
+ this.sslSocketFactory = provider.getSslSocketFactory();
+ this.trustManager = provider.getTrustManager();
+ } catch (IOException | java.security.GeneralSecurityException e) {
+ throw new SDKException("failed to load keystore from " + keystorePath, e);
+ }
return this;
}
@@ -223,8 +238,8 @@ private Interceptor getAuthInterceptor(RSAKey rsaKey) {
OIDCProviderMetadata providerMetadata;
try {
providerMetadata = OIDCProviderMetadata.resolve(issuer, httpRequest -> {
- if (sslFactory != null) {
- httpRequest.setSSLSocketFactory(sslFactory.getSslSocketFactory());
+ if (sslSocketFactory != null) {
+ httpRequest.setSSLSocketFactory(sslSocketFactory);
}
});
} catch (IOException | GeneralException e) {
@@ -234,7 +249,7 @@ private Interceptor getAuthInterceptor(RSAKey rsaKey) {
if (this.authzGrant == null) {
this.authzGrant = new ClientCredentialsGrant();
}
- var ts = new TokenSource(clientAuth, rsaKey, providerMetadata.getTokenEndpointURI(), this.authzGrant, sslFactory);
+ var ts = new TokenSource(clientAuth, rsaKey, providerMetadata.getTokenEndpointURI(), this.authzGrant, sslSocketFactory);
return new AuthInterceptor(ts);
}
@@ -344,7 +359,7 @@ public SDK.KAS kas() {
return new ServicesAndInternals(
authInterceptor,
- sslFactory == null ? null : sslFactory.getTrustManager().orElse(null),
+ trustManager,
services,
client,
srtSignerToUse);
@@ -378,6 +393,7 @@ private ProtocolClient getProtocolClient(String endpoint, OkHttpClient httpClien
return new ProtocolClient(new ConnectOkHttpClient(httpClient), protocolClientConfig);
}
+ @SuppressWarnings("deprecation")
private OkHttpClient getHttpClient() {
// using a single http client is apparently the best practice, subject to everyone wanting to
// have the same protocols
@@ -387,17 +403,24 @@ private OkHttpClient getHttpClient() {
// expect HTTP/2, and Connect protocol can communicate with gRPC servers over HTTP/2
httpClient.protocols(List.of(Protocol.H2_PRIOR_KNOWLEDGE));
}
- if (sslFactory != null) {
- var trustManager = sslFactory.getTrustManager();
- if (trustManager.isEmpty()) {
- throw new SDKException("SSL factory must have a trust manager");
+ if (sslSocketFactory != null) {
+ if (trustManager != null) {
+ httpClient.sslSocketFactory(sslSocketFactory, trustManager);
+ } else {
+ // Caller supplied an SSLSocketFactory without a matching trust manager (e.g. via
+ // sslFactory(SSLSocketFactory)). Falls back to OkHttp's reflection-based platform
+ // default trust manager — only the SSLSocketFactory governs the actual handshake.
+ httpClient.sslSocketFactory(sslSocketFactory);
}
- httpClient.sslSocketFactory(sslFactory.getSslSocketFactory(), trustManager.get());
}
return httpClient.build();
}
- SSLFactory getSslFactory() {
- return this.sslFactory;
+ SSLSocketFactory getSslFactory() {
+ return this.sslSocketFactory;
+ }
+
+ X509TrustManager getTrustManager() {
+ return this.trustManager;
}
}
diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java
index 3ee4ba22..a428703b 100644
--- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java
+++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java
@@ -11,7 +11,6 @@
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
-import org.bouncycastle.jce.interfaces.ECPublicKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -22,6 +21,7 @@
import java.nio.channels.SeekableByteChannel;
import java.nio.charset.StandardCharsets;
import java.security.*;
+import java.security.interfaces.ECPublicKey;
import java.text.ParseException;
import java.util.*;
diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TokenSource.java b/sdk/src/main/java/io/opentdf/platform/sdk/TokenSource.java
index 97e02a0c..587e2009 100644
--- a/sdk/src/main/java/io/opentdf/platform/sdk/TokenSource.java
+++ b/sdk/src/main/java/io/opentdf/platform/sdk/TokenSource.java
@@ -14,10 +14,10 @@
import com.nimbusds.oauth2.sdk.http.HTTPRequest;
import com.nimbusds.oauth2.sdk.http.HTTPResponse;
import com.nimbusds.oauth2.sdk.token.AccessToken;
-import nl.altindag.ssl.SSLFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.net.ssl.SSLSocketFactory;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
@@ -34,22 +34,22 @@ class TokenSource {
private final RSAKey rsaKey;
private final URI tokenEndpointURI;
private final AuthorizationGrant authzGrant;
- private final SSLFactory sslFactory;
+ private final SSLSocketFactory sslSocketFactory;
private static final Logger logger = LoggerFactory.getLogger(TokenSource.class);
/**
* Constructs a new TokenSource with the specified client authentication and RSA key.
*
- * @param clientAuth the client authentication to be used by the interceptor
- * @param rsaKey the RSA key to be used by the interceptor
- * @param sslFactory Optional SSLFactory for Requests
+ * @param clientAuth the client authentication to be used by the interceptor
+ * @param rsaKey the RSA key to be used by the interceptor
+ * @param sslSocketFactory Optional SSLSocketFactory for token endpoint requests
*/
- public TokenSource(ClientAuthentication clientAuth, RSAKey rsaKey, URI tokenEndpointURI, AuthorizationGrant authzGrant, SSLFactory sslFactory) {
+ public TokenSource(ClientAuthentication clientAuth, RSAKey rsaKey, URI tokenEndpointURI, AuthorizationGrant authzGrant, SSLSocketFactory sslSocketFactory) {
this.clientAuth = clientAuth;
this.rsaKey = rsaKey;
this.tokenEndpointURI = tokenEndpointURI;
- this.sslFactory = sslFactory;
+ this.sslSocketFactory = sslSocketFactory;
this.authzGrant = authzGrant;
}
@@ -108,8 +108,8 @@ private synchronized AccessToken getToken() {
TokenRequest tokenRequest = new TokenRequest(this.tokenEndpointURI,
clientAuth, authzGrant, null);
HTTPRequest httpRequest = tokenRequest.toHTTPRequest();
- if(sslFactory!=null){
- httpRequest.setSSLSocketFactory(sslFactory.getSslSocketFactory());
+ if (sslSocketFactory != null) {
+ httpRequest.setSSLSocketFactory(sslSocketFactory);
}
DPoPProofFactory dpopFactory = new DefaultDPoPProofFactory(rsaKey, JWSAlgorithm.RS256);
diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TrustProvider.java b/sdk/src/main/java/io/opentdf/platform/sdk/TrustProvider.java
new file mode 100644
index 00000000..9345ddc6
--- /dev/null
+++ b/sdk/src/main/java/io/opentdf/platform/sdk/TrustProvider.java
@@ -0,0 +1,274 @@
+package io.opentdf.platform.sdk;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509ExtendedTrustManager;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Builds {@link SSLSocketFactory} and {@link X509ExtendedTrustManager} instances for verifying
+ * X.509 certificate chains during TLS handshakes.
+ *
+ * Implemented entirely on top of provider-agnostic JCA APIs ({@link CertificateFactory},
+ * {@link KeyStore}, {@link TrustManagerFactory}, {@link SSLContext}). The actual cryptographic
+ * work is fulfilled by whichever {@link java.security.Provider} is registered with the JVM,
+ * including FIPS-mode providers.
+ */
+public final class TrustProvider {
+
+ private final SSLSocketFactory sslSocketFactory;
+ private final X509ExtendedTrustManager trustManager;
+ private final SSLContext sslContext;
+
+ private TrustProvider(SSLContext sslContext, X509ExtendedTrustManager trustManager) {
+ this.sslContext = sslContext;
+ this.trustManager = trustManager;
+ this.sslSocketFactory = sslContext.getSocketFactory();
+ }
+
+ public X509ExtendedTrustManager getTrustManager() {
+ return trustManager;
+ }
+
+ public SSLContext getSslContext() {
+ return sslContext;
+ }
+
+ public SSLSocketFactory getSslSocketFactory() {
+ return sslSocketFactory;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builds a {@link TrustProvider} that trusts JVM default cacerts plus every {@code .pem} or
+ * {@code .crt} certificate found in the supplied directory.
+ */
+ public static TrustProvider fromDirectory(String certsDirPath) throws IOException, GeneralSecurityException {
+ File certsDir = new File(certsDirPath);
+ File[] certFiles = certsDir.listFiles((dir, name) -> name.endsWith(".pem") || name.endsWith(".crt"));
+ if (certFiles == null) {
+ throw new IOException("not a directory or unreadable: " + certsDirPath);
+ }
+ Builder builder = builder().withDefaultTrustMaterial();
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ for (File certFile : certFiles) {
+ try (InputStream in = new FileInputStream(certFile)) {
+ Collection extends Certificate> certs = cf.generateCertificates(in);
+ List x509s = new ArrayList<>(certs.size());
+ for (Certificate c : certs) {
+ if (c instanceof X509Certificate) {
+ x509s.add((X509Certificate) c);
+ }
+ }
+ builder.withTrustMaterial(x509s.toArray(new X509Certificate[0]));
+ }
+ }
+ return builder.build();
+ }
+
+ /**
+ * Builds a {@link TrustProvider} that trusts JVM default cacerts plus the trusted-certificate
+ * entries in the supplied keystore.
+ */
+ public static TrustProvider fromKeyStore(Path keystorePath, char[] password) throws IOException, GeneralSecurityException {
+ if (!Files.isRegularFile(keystorePath)) {
+ throw new IOException("keystore not found: " + keystorePath);
+ }
+ KeyStore ks;
+ try (InputStream in = Files.newInputStream(keystorePath)) {
+ ks = loadKeyStore(in, password);
+ }
+ return builder().withDefaultTrustMaterial().withTrustMaterial(ks).build();
+ }
+
+ /**
+ * Builds a {@link TrustProvider} that accepts every server certificate. Intended only for
+ * tests and {@code --insecure} CLI flows.
+ */
+ public static TrustProvider insecure() {
+ try {
+ SSLContext ctx = SSLContext.getInstance("TLS");
+ X509ExtendedTrustManager trustAll = new InsecureTrustManager();
+ ctx.init(new KeyManager[0], new TrustManager[]{trustAll}, new SecureRandom());
+ return new TrustProvider(ctx, trustAll);
+ } catch (GeneralSecurityException e) {
+ throw new IllegalStateException("failed to build insecure TrustProvider", e);
+ }
+ }
+
+ private static KeyStore loadKeyStore(InputStream in, char[] password)
+ throws IOException, GeneralSecurityException {
+ // Try JKS first since it remains the JVM default; fall back to PKCS12 which is portable
+ // across both bcprov-jdk18on and bc-fips. We do not pin a provider; whichever provider is
+ // registered fulfills the request.
+ byte[] bytes = readAll(in);
+ KeyStoreException last = null;
+ for (String type : new String[]{KeyStore.getDefaultType(), "JKS", "PKCS12"}) {
+ try {
+ KeyStore ks = KeyStore.getInstance(type);
+ ks.load(new java.io.ByteArrayInputStream(bytes), password);
+ return ks;
+ } catch (KeyStoreException e) {
+ last = e;
+ } catch (IOException | NoSuchAlgorithmException | CertificateException e) {
+ // wrong format or wrong password — try next type
+ last = new KeyStoreException(e);
+ }
+ }
+ throw last != null ? last : new KeyStoreException("could not load keystore");
+ }
+
+ private static byte[] readAll(InputStream in) throws IOException {
+ java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream();
+ byte[] buf = new byte[8192];
+ int n;
+ while ((n = in.read(buf)) >= 0) {
+ out.write(buf, 0, n);
+ }
+ return out.toByteArray();
+ }
+
+ private static X509ExtendedTrustManager extractTrustManager(KeyStore trustStore)
+ throws GeneralSecurityException {
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init(trustStore);
+ for (TrustManager tm : tmf.getTrustManagers()) {
+ if (tm instanceof X509ExtendedTrustManager) {
+ return (X509ExtendedTrustManager) tm;
+ }
+ }
+ throw new NoSuchAlgorithmException("no X509ExtendedTrustManager available from provider");
+ }
+
+ public static final class Builder {
+ private boolean includeDefault;
+ private final List keyStores = new ArrayList<>();
+ private final List certificates = new ArrayList<>();
+
+ private Builder() {
+ }
+
+ /**
+ * Include the JVM default cacerts (i.e. those returned by initialising a
+ * {@link TrustManagerFactory} with a {@code null} keystore).
+ */
+ public Builder withDefaultTrustMaterial() {
+ this.includeDefault = true;
+ return this;
+ }
+
+ public Builder withTrustMaterial(X509Certificate... certs) {
+ if (certs != null) {
+ Collections.addAll(this.certificates, certs);
+ }
+ return this;
+ }
+
+ public Builder withTrustMaterial(Collection certs) {
+ if (certs != null) {
+ this.certificates.addAll(certs);
+ }
+ return this;
+ }
+
+ public Builder withTrustMaterial(KeyStore keyStore) {
+ if (keyStore != null) {
+ this.keyStores.add(keyStore);
+ }
+ return this;
+ }
+
+ public Builder withTrustMaterial(Path keystorePath, char[] password) throws IOException, GeneralSecurityException {
+ try (InputStream in = Files.newInputStream(keystorePath)) {
+ this.keyStores.add(loadKeyStore(in, password));
+ }
+ return this;
+ }
+
+ public TrustProvider build() {
+ try {
+ List trustManagers = new ArrayList<>();
+
+ if (includeDefault) {
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init((KeyStore) null);
+ for (TrustManager tm : tmf.getTrustManagers()) {
+ if (tm instanceof X509ExtendedTrustManager) {
+ trustManagers.add((X509ExtendedTrustManager) tm);
+ }
+ }
+ }
+
+ for (KeyStore ks : keyStores) {
+ trustManagers.add(extractTrustManager(ks));
+ }
+
+ if (!certificates.isEmpty()) {
+ KeyStore custom = newEmptyKeyStore();
+ int i = 0;
+ for (X509Certificate cert : certificates) {
+ custom.setCertificateEntry("trust-anchor-" + (i++), cert);
+ }
+ trustManagers.add(extractTrustManager(custom));
+ }
+
+ if (trustManagers.isEmpty()) {
+ throw new IllegalStateException("TrustProvider requires at least one source of trust material");
+ }
+
+ X509ExtendedTrustManager combined = trustManagers.size() == 1
+ ? trustManagers.get(0)
+ : new CompositeX509ExtendedTrustManager(trustManagers);
+
+ SSLContext ctx = SSLContext.getInstance("TLS");
+ ctx.init(new KeyManager[0], new TrustManager[]{combined}, new SecureRandom());
+ return new TrustProvider(ctx, combined);
+ } catch (GeneralSecurityException | IOException e) {
+ throw new IllegalStateException("failed to build TrustProvider", e);
+ }
+ }
+
+ private static KeyStore newEmptyKeyStore() throws GeneralSecurityException, IOException {
+ // PKCS12 is supported by both stock JDK and BC (FIPS and non-FIPS).
+ KeyStore ks = KeyStore.getInstance("PKCS12");
+ ks.load(null, null);
+ return ks;
+ }
+ }
+
+ private static final class InsecureTrustManager extends X509ExtendedTrustManager {
+ private static final X509Certificate[] EMPTY = new X509Certificate[0];
+
+ @Override public void checkClientTrusted(X509Certificate[] chain, String authType) { }
+ @Override public void checkClientTrusted(X509Certificate[] chain, String authType, java.net.Socket socket) { }
+ @Override public void checkClientTrusted(X509Certificate[] chain, String authType, javax.net.ssl.SSLEngine engine) { }
+ @Override public void checkServerTrusted(X509Certificate[] chain, String authType) { }
+ @Override public void checkServerTrusted(X509Certificate[] chain, String authType, java.net.Socket socket) { }
+ @Override public void checkServerTrusted(X509Certificate[] chain, String authType, javax.net.ssl.SSLEngine engine) { }
+ @Override public X509Certificate[] getAcceptedIssuers() { return EMPTY; }
+ }
+}
diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/CryptoProviderSetupExtension.java b/sdk/src/test/java/io/opentdf/platform/sdk/CryptoProviderSetupExtension.java
new file mode 100644
index 00000000..3a6d0d9e
--- /dev/null
+++ b/sdk/src/test/java/io/opentdf/platform/sdk/CryptoProviderSetupExtension.java
@@ -0,0 +1,18 @@
+package io.opentdf.platform.sdk;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.junit.jupiter.api.extension.BeforeAllCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+
+import java.security.Security;
+
+public class CryptoProviderSetupExtension implements BeforeAllCallback {
+ private BouncyCastleProvider securityProvider;
+
+ @Override
+ public void beforeAll(ExtensionContext extensionContext) throws Exception {
+ if (this.securityProvider == null) {
+ Security.addProvider(this.securityProvider = new BouncyCastleProvider());
+ }
+ }
+}
diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java
index d454b6c6..4c9265a1 100644
--- a/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java
+++ b/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java
@@ -1,14 +1,10 @@
package io.opentdf.platform.sdk;
-import org.bouncycastle.jce.interfaces.ECPrivateKey;
-import org.bouncycastle.jce.interfaces.ECPublicKey;
import org.junit.jupiter.api.Test;
-import java.io.IOException;
import java.nio.charset.StandardCharsets;
-import java.security.*;
-import java.security.cert.CertificateException;
-import java.security.spec.InvalidKeySpecException;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
import java.util.Arrays;
import java.util.Base64;
@@ -51,13 +47,13 @@ public class ECKeys {
void ecPublicKeyInPemformat() {
ECKeyPair keyPairA = new ECKeyPair();
- String keypairAPubicKey = keyPairA.publicKeyInPEMFormat();
+ String keypairAPublicKey = keyPairA.publicKeyInPEMFormat();
String keypairAPrivateKey = keyPairA.privateKeyInPEMFormat();
- ECPublicKey publicKeyA = ECKeyPair.publicKeyFromPem(keypairAPubicKey);
+ ECPublicKey publicKeyA = ECKeyPair.publicKeyFromPem(keypairAPublicKey);
ECPrivateKey privateKeyA = ECKeyPair.privateKeyFromPem(keypairAPrivateKey);
- System.out.println(keypairAPubicKey);
+ System.out.println(keypairAPublicKey);
System.out.println(keypairAPrivateKey);
byte[] compressedKey1 = keyPairA.compressECPublickey();
@@ -83,45 +79,6 @@ void ecPublicKeyInPemformat() {
System.out.println(Arrays.toString(symmetricKey1));
}
- @Test
- void extractPemPubKeyFromX509() throws CertificateException, IOException, NoSuchAlgorithmException,
- InvalidKeySpecException, NoSuchProviderException, InvalidAlgorithmParameterException, InvalidKeyException {
- String x509ECPubKey = "-----BEGIN CERTIFICATE-----\n" +
- "MIIBCzCBsgIJAK3Uxk7fP5oWMAoGCCqGSM49BAMCMA4xDDAKBgNVBAMMA2thczAe\n" +
- "Fw0yMzA0MjQxNzQ2MTVaFw0yNDA0MjMxNzQ2MTVaMA4xDDAKBgNVBAMMA2thczBZ\n" +
- "MBMGByqGSM49AgEGCCqGSM49AwEHA0IABL//OvkSC1ji2w7AUrj27BxN3K6hhN4B\n" +
- "YRb45lYoMsihIxhDmMDAZTgoaDyNJG59VrJE/yoM9KuiXV8a+82+OwwwCgYIKoZI\n" +
- "zj0EAwIDSAAwRQIhAItk5SmcWSg06tnOCEqTa6UsChaycX/cmAT8PTDRnaRcAiAl\n" +
- "Vr2EvlA2x5mWFE/+nDdxxzljYjLZuSDQMEI/J6u0/Q==\n" +
- "-----END CERTIFICATE-----";
- String pubKey = ECKeyPair.getPEMPublicKeyFromX509Cert(x509ECPubKey);
- System.out.println(pubKey);
-
- ECPublicKey publicKey = ECKeyPair.publicKeyFromPem(pubKey);
- byte[] compressedKey = publicKey.getQ().getEncoded(true);
- System.out.println(Arrays.toString(compressedKey));
-
- compressedKey = ECKeyPair.compressECPublickey(pubKey);
- System.out.println(Arrays.toString(compressedKey));
- System.out.println(compressedKey.length);
-
- ECKeyPair keyPair = new ECKeyPair();
-
- String keypairPubicKey = keyPair.publicKeyInPEMFormat();
- String keypairPrivateKey = keyPair.privateKeyInPEMFormat();
- System.out.println(keypairPubicKey);
- System.out.println(keypairPrivateKey);
-
- byte[] symmetricKey = ECKeyPair.computeECDHKey(publicKey, ECKeyPair.privateKeyFromPem(keypairPrivateKey));
- System.out.println(Arrays.toString(symmetricKey));
-
- byte[] key = ECKeyPair.calculateHKDF(ECKeys.salt.getBytes(StandardCharsets.UTF_8), symmetricKey);
- System.out.println(Arrays.toString(key));
- System.out.println(key.length);
-
- assertThat(key.length).isEqualTo(32); // SHA-256 produces a 32-byte key
- }
-
@Test
void createSymmetricKeysWithOtherCurves() {
ECKeyPair pubPair = new ECKeyPair(ECCurve.SECP384R1, ECKeyPair.ECAlgorithm.ECDH);
@@ -147,20 +104,20 @@ void testECDH() {
byte[] symmetricKey = ECKeyPair.computeECDHKey(kasPubKey, sdkPriKey);
byte[] key = ECKeyPair.calculateHKDF(ECKeys.salt.getBytes(StandardCharsets.UTF_8), symmetricKey);
String encodedKey = Base64.getEncoder().encodeToString(key);
- assertEquals(encodedKey, expectedKey);
+ assertEquals(expectedKey, encodedKey);
// KAS side
symmetricKey = ECKeyPair.computeECDHKey(sdkPubKey, kasPriKey);
key = ECKeyPair.calculateHKDF(ECKeys.salt.getBytes(StandardCharsets.UTF_8), symmetricKey);
encodedKey = Base64.getEncoder().encodeToString(key);
- assertEquals(encodedKey, expectedKey);
+ assertEquals(expectedKey, encodedKey);
byte[] ecPoint = ECKeyPair.compressECPublickey(ECKeys.sdkPublicKey);
String encodeECPoint = Base64.getEncoder().encodeToString(ecPoint);
- assertEquals(encodeECPoint, "Al3vx59pBnP8tRxuUFw18aK9ym6rFrxZRhpVQytUQ+Kg");
+ assertEquals("Al3vx59pBnP8tRxuUFw18aK9ym6rFrxZRhpVQytUQ+Kg", encodeECPoint);
String publicKey = ECKeyPair.publicKeyFromECPoint(ecPoint,
- SECP256R1.name());
+ SECP256R1.getCurveName());
assertArrayEquals(ECKeys.sdkPublicKey.toCharArray(), publicKey.toCharArray());
}
diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/SDKBuilderTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/SDKBuilderTest.java
index cebc9928..9b365543 100644
--- a/sdk/src/test/java/io/opentdf/platform/sdk/SDKBuilderTest.java
+++ b/sdk/src/test/java/io/opentdf/platform/sdk/SDKBuilderTest.java
@@ -20,9 +20,6 @@
import io.opentdf.platform.wellknownconfiguration.GetWellKnownConfigurationRequest;
import io.opentdf.platform.wellknownconfiguration.GetWellKnownConfigurationResponse;
import io.opentdf.platform.wellknownconfiguration.WellKnownServiceGrpc;
-import nl.altindag.ssl.SSLFactory;
-import nl.altindag.ssl.pem.util.PemUtils;
-import nl.altindag.ssl.util.KeyStoreUtils;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.tls.HandshakeCertificates;
@@ -30,6 +27,8 @@
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Test;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.X509TrustManager;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
@@ -40,6 +39,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyStore;
+import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Base64;
@@ -70,24 +70,31 @@ void testDirCertsSSLContext() throws Exception {
IOUtils.write(EXAMPLE_COM_PEM, fos);
fos.close();
SDKBuilder builder = SDKBuilder.newBuilder().sslFactoryFromDirectory(certDirPath.toAbsolutePath().toString());
- SSLFactory sslFactory = builder.getSslFactory();
- assertNotNull(sslFactory);
- X509Certificate[] acceptedIssuers = sslFactory.getTrustManager().get().getAcceptedIssuers();
+ SSLSocketFactory sslSocketFactory = builder.getSslFactory();
+ assertNotNull(sslSocketFactory);
+ X509TrustManager trustManager = builder.getTrustManager();
+ assertNotNull(trustManager);
+ X509Certificate[] acceptedIssuers = trustManager.getAcceptedIssuers();
assertEquals(1, Arrays.stream(acceptedIssuers).filter(x -> x.getIssuerX500Principal().getName()
.equals("CN=example.com")).count());
}
@Test
void testKeystoreSSLContext() throws Exception {
- KeyStore keystore = KeyStoreUtils.createKeyStore();
- keystore.setCertificateEntry("example.com", PemUtils.parseCertificate(EXAMPLE_COM_PEM).get(0));
+ KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
+ keystore.load(null, null);
+ X509Certificate cert = (X509Certificate) CertificateFactory.getInstance("X.509")
+ .generateCertificate(new ByteArrayInputStream(EXAMPLE_COM_PEM.getBytes(StandardCharsets.UTF_8)));
+ keystore.setCertificateEntry("example.com", cert);
Path keyStorePath = Files.createTempFile("ca", "jks");
keystore.store(new FileOutputStream(keyStorePath.toAbsolutePath().toString()), "foo".toCharArray());
SDKBuilder builder = SDKBuilder.newBuilder().sslFactoryFromKeyStore(keyStorePath.toAbsolutePath().toString(),
"foo");
- SSLFactory sslFactory = builder.getSslFactory();
- assertNotNull(sslFactory);
- X509Certificate[] acceptedIssuers = sslFactory.getTrustManager().get().getAcceptedIssuers();
+ SSLSocketFactory sslSocketFactory = builder.getSslFactory();
+ assertNotNull(sslSocketFactory);
+ X509TrustManager trustManager = builder.getTrustManager();
+ assertNotNull(trustManager);
+ X509Certificate[] acceptedIssuers = trustManager.getAcceptedIssuers();
assertEquals(1, Arrays.stream(acceptedIssuers).filter(x -> x.getIssuerX500Principal().getName()
.equals("CN=example.com")).count());
@@ -305,8 +312,11 @@ public ServerCall.Listener interceptCall(ServerCall