summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@verizonmedia.com>2021-05-28 17:33:46 +0200
committerBjørn Christian Seime <bjorncs@verizonmedia.com>2021-05-28 18:12:39 +0200
commit36e2c46d87ed9417339afbc515c92e857c4a8fb6 (patch)
treea46cccbd41e642b8e26125746be8e1b3ea7f3de9
parent27a3b98865f64472d116cb8505c41059093b41de (diff)
Fix bugs in SslContextBuilder and add unit test
-rw-r--r--vespa-feed-client/src/main/java/ai/vespa/feed/client/SslContextBuilder.java5
-rw-r--r--vespa-feed-client/src/test/java/ai/vespa/feed/client/SslContextBuilderTest.java88
2 files changed, 91 insertions, 2 deletions
diff --git a/vespa-feed-client/src/main/java/ai/vespa/feed/client/SslContextBuilder.java b/vespa-feed-client/src/main/java/ai/vespa/feed/client/SslContextBuilder.java
index 1a5f27c5d66..7200d5fd943 100644
--- a/vespa-feed-client/src/main/java/ai/vespa/feed/client/SslContextBuilder.java
+++ b/vespa-feed-client/src/main/java/ai/vespa/feed/client/SslContextBuilder.java
@@ -34,7 +34,7 @@ import java.util.List;
*/
class SslContextBuilder {
- private static final BouncyCastleProvider bcProvider = new BouncyCastleProvider();
+ static final BouncyCastleProvider bcProvider = new BouncyCastleProvider();
private Path certificateFile;
private Path privateKeyFile;
@@ -54,6 +54,7 @@ class SslContextBuilder {
SSLContext build() throws IOException {
try {
KeyStore keystore = KeyStore.getInstance("PKCS12");
+ keystore.load(null);
if (certificateFile != null && privateKeyFile != null) {
keystore.setKeyEntry("cert", privateKey(privateKeyFile), new char[0], certificates(certificateFile));
}
@@ -64,7 +65,7 @@ class SslContextBuilder {
kmf.init(keystore, new char[0]);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keystore);
- SSLContext sslContext = SSLContext.getDefault();
+ SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return sslContext;
} catch (GeneralSecurityException e) {
diff --git a/vespa-feed-client/src/test/java/ai/vespa/feed/client/SslContextBuilderTest.java b/vespa-feed-client/src/test/java/ai/vespa/feed/client/SslContextBuilderTest.java
new file mode 100644
index 00000000000..e930c602ec7
--- /dev/null
+++ b/vespa-feed-client/src/test/java/ai/vespa/feed/client/SslContextBuilderTest.java
@@ -0,0 +1,88 @@
+package ai.vespa.feed.client;// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.util.io.pem.PemObject;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import javax.net.ssl.SSLContext;
+import javax.security.auth.x500.X500Principal;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.security.spec.ECGenParameterSpec;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * @author bjorncs
+ */
+class SslContextBuilderTest {
+
+ private static Path certificateFile;
+ private static Path privateKeyFile;
+
+ @BeforeAll
+ static void createPemFiles(@TempDir Path tempDirectory) throws GeneralSecurityException, OperatorCreationException, IOException {
+ KeyPair keypair = createKeypair();
+ X509Certificate certificate = createCertificate(keypair);
+ certificateFile = tempDirectory.resolve("cert.pem");
+ privateKeyFile = tempDirectory.resolve("key.pem");
+ writePem(certificateFile, "CERTIFICATE", certificate.getEncoded());
+ writePem(privateKeyFile, "PRIVATE KEY", keypair.getPrivate().getEncoded());
+ }
+
+ @Test
+ void successfully_constructs_sslcontext_from_pem_files() {
+ SSLContext sslContext = assertDoesNotThrow(() ->
+ new SslContextBuilder()
+ .withCaCertificates(certificateFile)
+ .withCertificateAndKey(certificateFile, privateKeyFile)
+ .build());
+ assertEquals("TLS", sslContext.getProtocol());
+ }
+
+ private static void writePem(Path file, String type, byte[] asn1DerEncodedObject) throws IOException {
+ try (BufferedWriter fileWriter = Files.newBufferedWriter(file);
+ JcaPEMWriter pemWriter = new JcaPEMWriter(fileWriter)) {
+ pemWriter.writeObject(new PemObject(type, asn1DerEncodedObject));
+ pemWriter.flush();
+ }
+ }
+
+ private static KeyPair createKeypair() throws GeneralSecurityException {
+ KeyPairGenerator generator = KeyPairGenerator.getInstance("EC", SslContextBuilder.bcProvider);
+ generator.initialize(new ECGenParameterSpec("prime256v1"));
+ return generator.generateKeyPair();
+ }
+
+ private static X509Certificate createCertificate(KeyPair keypair) throws OperatorCreationException, CertificateException {
+ JcaX509v3CertificateBuilder jcaCertBuilder = new JcaX509v3CertificateBuilder(
+ new X500Principal("CN=localhost"), BigInteger.ONE, Date.from(Instant.EPOCH),
+ Date.from(Instant.EPOCH.plus(100_000, ChronoUnit.DAYS)), new X500Principal("CN=localhost"), keypair.getPublic());
+ ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256withECDSA")
+ .setProvider(SslContextBuilder.bcProvider)
+ .build(keypair.getPrivate());
+ return new JcaX509CertificateConverter()
+ .setProvider(SslContextBuilder.bcProvider)
+ .getCertificate(jcaCertBuilder.build(contentSigner));
+ }
+
+} \ No newline at end of file