diff options
author | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2021-05-28 17:33:46 +0200 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2021-05-28 18:12:39 +0200 |
commit | 36e2c46d87ed9417339afbc515c92e857c4a8fb6 (patch) | |
tree | a46cccbd41e642b8e26125746be8e1b3ea7f3de9 | |
parent | 27a3b98865f64472d116cb8505c41059093b41de (diff) |
Fix bugs in SslContextBuilder and add unit test
-rw-r--r-- | vespa-feed-client/src/main/java/ai/vespa/feed/client/SslContextBuilder.java | 5 | ||||
-rw-r--r-- | vespa-feed-client/src/test/java/ai/vespa/feed/client/SslContextBuilderTest.java | 88 |
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 |