diff --git a/CHANGELOG.md b/CHANGELOG.md index 28429c4..f691078 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ ## 0.4.0 [development] +* [feature] Option to provide a trusted CA certificate (#2) * [feature] Deletion, revocation and renewal of secrets (#3) * [feature] Token creation (#4) * [feature] AppRole auth backend supported (#5) diff --git a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java index 6a71cd2..2573a59 100644 --- a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java +++ b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java @@ -30,10 +30,8 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; +import javax.net.ssl.*; +import java.io.*; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.util.*; @@ -65,11 +63,12 @@ public class HTTPVaultConnector implements VaultConnector { private final ObjectMapper jsonMapper; - private final String baseURL; /* Base URL of Vault */ + private final String baseURL; /* Base URL of Vault */ + private final SSLContext sslContext; /* Custom SSLSocketFactory */ - private boolean authorized = false; /* authorization status */ - private String token; /* current token */ - private long tokenTTL = 0; /* expiration time for current token */ + private boolean authorized = false; /* authorization status */ + private String token; /* current token */ + private long tokenTTL = 0; /* expiration time for current token */ /** * Create connector using hostname and schema. @@ -93,12 +92,12 @@ public class HTTPVaultConnector implements VaultConnector { } /** - * Create connector using hostname, schame, port and path. + * Create connector using hostname, schema, port and path. * * @param hostname The hostname * @param useTLS If TRUE, use HTTPS, otherwise HTTP * @param port The port - * @param prefix HTTP API prefix (default: /v1/" + * @param prefix HTTP API prefix (default: /v1/) */ public HTTPVaultConnector(String hostname, boolean useTLS, Integer port, String prefix) { this(((useTLS) ? "https" : "http") + @@ -107,13 +106,40 @@ public class HTTPVaultConnector implements VaultConnector { prefix); } + /** + * Create connector using hostname, schema, port, path and trusted certificate. + * + * @param hostname The hostname + * @param useTLS If TRUE, use HTTPS, otherwise HTTP + * @param port The port + * @param prefix HTTP API prefix (default: /v1/) + * @param sslContext Custom SSL Context + */ + public HTTPVaultConnector(String hostname, boolean useTLS, Integer port, String prefix, SSLContext sslContext) { + this(((useTLS) ? "https" : "http") + + "://" + hostname + + ((port != null) ? ":" + port : "") + + prefix, + sslContext); + } + /** * Create connector using full URL. * * @param baseURL The URL */ public HTTPVaultConnector(String baseURL) { + this(baseURL, null); + } + + /** + * Create connector using full URL and trusted certificate. + * + * @param baseURL The URL + */ + public HTTPVaultConnector(String baseURL, SSLContext sslContext) { this.baseURL = baseURL; + this.sslContext = sslContext; this.jsonMapper = new ObjectMapper(); } @@ -669,7 +695,7 @@ public class HTTPVaultConnector implements VaultConnector { base.addHeader("accept", "application/json"); HttpResponse response = null; - try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) { + try (CloseableHttpClient httpClient = HttpClientBuilder.create().setSSLContext(sslContext).build()) { response = httpClient.execute(base); /* Check if response is valid */ if (response == null) diff --git a/src/main/java/de/stklcode/jvault/connector/exception/TlsException.java b/src/main/java/de/stklcode/jvault/connector/exception/TlsException.java new file mode 100644 index 0000000..860f754 --- /dev/null +++ b/src/main/java/de/stklcode/jvault/connector/exception/TlsException.java @@ -0,0 +1,51 @@ +/* + * Copyright 2016 Stefan Kalscheuer + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.stklcode.jvault.connector.exception; + +/** + * Exception thrown on errors with TLS connection. + * + * @author Stefan Kalscheuer + * @since 0.4.0 + */ +public class TlsException extends VaultConnectorException { + private Integer statusCode; + private String response; + + public TlsException() { + } + + public TlsException(String message) { + super(message); + } + + public TlsException(Throwable cause) { + super(cause); + } + + public TlsException(String message, Throwable cause) { + super(message, cause); + } + + public Integer getStatusCode() { + return statusCode; + } + + public String getResponse() { + return response; + } +} diff --git a/src/main/java/de/stklcode/jvault/connector/factory/HTTPVaultConnectorFactory.java b/src/main/java/de/stklcode/jvault/connector/factory/HTTPVaultConnectorFactory.java index 5c5edd6..fe73710 100644 --- a/src/main/java/de/stklcode/jvault/connector/factory/HTTPVaultConnectorFactory.java +++ b/src/main/java/de/stklcode/jvault/connector/factory/HTTPVaultConnectorFactory.java @@ -17,12 +17,26 @@ package de.stklcode.jvault.connector.factory; import de.stklcode.jvault.connector.HTTPVaultConnector; +import de.stklcode.jvault.connector.exception.TlsException; +import de.stklcode.jvault.connector.exception.VaultConnectorException; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.*; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; /** * Vault Connector Factory implementation for HTTP Vault connectors. * - * @author Stefan Kalscheuer - * @since 0.1 + * @author Stefan Kalscheuer + * @since 0.1 */ public class HTTPVaultConnectorFactory extends VaultConnectorFactory { public static final String DEFAULT_HOST = "127.0.0.1"; @@ -34,6 +48,7 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory { private Integer port; private boolean tls; private String prefix; + private SSLContext sslContext; /** * Default empty constructor. @@ -48,8 +63,9 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory { /** * Set hostname (default: 127.0.0.1) - * @param host Hostname or IP address - * @return self + * + * @param host Hostname or IP address + * @return self */ public HTTPVaultConnectorFactory withHost(String host) { this.host = host; @@ -58,8 +74,9 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory { /** * Set port (default: 8200) - * @param port Vault TCP port - * @return self + * + * @param port Vault TCP port + * @return self */ public HTTPVaultConnectorFactory withPort(Integer port) { this.port = port; @@ -68,8 +85,9 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory { /** * Set TLS usage (default: TRUE) - * @param useTLS use TLS or not - * @return self + * + * @param useTLS use TLS or not + * @return self */ public HTTPVaultConnectorFactory withTLS(boolean useTLS) { this.tls = useTLS; @@ -78,7 +96,8 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory { /** * Convenience Method for TLS usage (enabled by default) - * @return self + * + * @return self */ public HTTPVaultConnectorFactory withTLS() { return withTLS(true); @@ -86,7 +105,8 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory { /** * Convenience Method for NOT using TLS - * @return self + * + * @return self */ public HTTPVaultConnectorFactory withoutTLS() { return withTLS(false); @@ -94,16 +114,98 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory { /** * Set API prefix. Default is "/v1/" and changes should not be necessary for current state of development. - * @param prefix Vault API prefix (default: "/v1/" - * @return self + * + * @param prefix Vault API prefix (default: "/v1/" + * @return self */ public HTTPVaultConnectorFactory withPrefix(String prefix) { this.prefix = prefix; return this; } + /** + * Add a trusted CA certifiate for HTTPS connections. + * + * @param cert path to certificate file + * @return self + * @since 0.4.0 + */ + public HTTPVaultConnectorFactory withTrustedCA(Path cert) throws VaultConnectorException { + return withSslContext(createSslContext(cert)); + } + + /** + * Add a custom SSL context. + * Overwrites certificates set by {@link #withTrustedCA}. + * + * @param sslContext the SSL context + * @return self + * @since 0.4.0 + */ + public HTTPVaultConnectorFactory withSslContext(SSLContext sslContext) { + this.sslContext = sslContext; + return this; + } + @Override public HTTPVaultConnector build() { - return new HTTPVaultConnector(host, tls, port, prefix); + return new HTTPVaultConnector(host, tls, port, prefix, sslContext); + } + + /** + * Create SSL Context trusting only provided certificate. + * + * @param trustedCert Path to trusted CA certificate + * @return SSL context + * @throws TlsException on errors + * @since 0.4.0 + */ + private SSLContext createSslContext(Path trustedCert) throws TlsException { + try { + SSLContext context = SSLContext.getInstance("TLS"); + context.init(null, createTrustManager(trustedCert), new SecureRandom()); + return context; + } catch (NoSuchAlgorithmException | KeyManagementException e) { + throw new TlsException("Unable to intialize SSLContext", e); + } + } + + /** + * Create a custom TrustManager for given CA certificate file. + * + * @param trustedCert Path to trusted CA certificate + * @return TrustManger + * @throws TlsException on error + * @since 0.4.0 + */ + private TrustManager[] createTrustManager(Path trustedCert) throws TlsException { + try { + /* Create Keystore with trusted certificate */ + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null, null); + keyStore.setCertificateEntry("trustedCert", certificateFromFile(trustedCert)); + /* Initialize TrustManager */ + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(keyStore); + return tmf.getTrustManagers(); + } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) { + throw new TlsException("Unable to initialize TrustManager", e); + } + } + + /** + * Read given certificate file to X.509 certificate. + * + * @param certFile Path to certificate file + * @return X.509 Certificate object + * @throws TlsException on error + * @since 0.4.0 + */ + private X509Certificate certificateFromFile(Path certFile) throws TlsException { + try (InputStream is = Files.newInputStream(certFile)) { + return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is); + } catch (IOException | CertificateException e) { + throw new TlsException("Unable to read certificate.", e); + } } } diff --git a/src/main/java/de/stklcode/jvault/connector/factory/VaultConnectorFactory.java b/src/main/java/de/stklcode/jvault/connector/factory/VaultConnectorFactory.java index 0b62844..05b2277 100644 --- a/src/main/java/de/stklcode/jvault/connector/factory/VaultConnectorFactory.java +++ b/src/main/java/de/stklcode/jvault/connector/factory/VaultConnectorFactory.java @@ -17,6 +17,7 @@ package de.stklcode.jvault.connector.factory; import de.stklcode.jvault.connector.VaultConnector; +import de.stklcode.jvault.connector.exception.VaultConnectorException; /** * Abstract Vault Connector Factory interface. diff --git a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java index bccdeaa..35bcf8e 100644 --- a/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java +++ b/src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorTest.java @@ -19,6 +19,7 @@ package de.stklcode.jvault.connector; import de.stklcode.jvault.connector.exception.InvalidResponseException; import de.stklcode.jvault.connector.model.*; import de.stklcode.jvault.connector.model.response.*; +import de.stklcode.jvault.connector.factory.HTTPVaultConnectorFactory; import de.stklcode.jvault.connector.test.Credentials; import de.stklcode.jvault.connector.test.VaultConfiguration; import de.stklcode.jvault.connector.exception.InvalidRequestException; @@ -27,13 +28,17 @@ import de.stklcode.jvault.connector.exception.VaultConnectorException; import de.stklcode.jvault.connector.factory.VaultConnectorFactory; import org.junit.*; import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.net.ServerSocket; -import java.util.*; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import static org.hamcrest.Matchers.*; import static org.hamcrest.core.Is.is; @@ -43,8 +48,8 @@ import static org.junit.Assume.*; /** * JUnit Test for HTTP Vault connector. * - * @author Stefan Kalscheuer - * @since 0.1 + * @author Stefan Kalscheuer + * @since 0.1 */ public class HTTPVaultConnectorTest { private static String KEY = "81011a8061e5c028bd0d9503eeba40bd9054b9af0408d080cb24f57405c27a61"; @@ -66,27 +71,37 @@ public class HTTPVaultConnectorTest { private VaultConnector connector; @Rule - public TemporaryFolder tmpDir = new TemporaryFolder(); + public TemporaryFolder tmpDir = new TemporaryFolder(); + + @Rule + public TestName testName = new TestName(); /** * Initialize Vault instance with generated configuration and provided file backend. * Requires "vault" binary to be in current user's executable path. Not using MLock, so no extended rights required. */ @Before - public void setUp() { + public void setUp() throws VaultConnectorException { + /* Determine, if TLS is required */ + boolean isTls = testName.getMethodName().equals("tlsConnectionTest"); + /* Initialize Vault */ - VaultConfiguration config = initializeVault(); + VaultConfiguration config = initializeVault(isTls); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } + /* Initialize connector */ - connector = VaultConnectorFactory.httpFactory() + HTTPVaultConnectorFactory factory = VaultConnectorFactory.httpFactory() .withHost(config.getHost()) .withPort(config.getPort()) - .withoutTLS() - .build(); + .withTLS(isTls); + if (isTls) + factory.withTrustedCA(Paths.get(getClass().getResource("/tls/ca.pem").getPath())); + connector = factory.build(); + /* Unseal Vault and check result */ SealResponse sealStatus = connector.unseal(KEY); assumeNotNull(sealStatus); @@ -107,8 +122,7 @@ public class HTTPVaultConnectorTest { /* Authenticate as valid user */ try { connector.authToken(TOKEN_ROOT); - } - catch(VaultConnectorException ignored) { + } catch (VaultConnectorException ignored) { } assumeTrue(connector.isAuthorized()); @@ -152,8 +166,7 @@ public class HTTPVaultConnectorTest { try { connector.authUserPass("foo", "bar"); fail("Logged in with invalid credentials"); - } - catch(VaultConnectorException ignored) { + } catch (VaultConnectorException ignored) { } try { @@ -177,8 +190,7 @@ public class HTTPVaultConnectorTest { try { boolean res = connector.registerAppId(APP_ID, "user", "App Name"); assertThat("Failed to register App-ID", res, is(true)); - } - catch (VaultConnectorException e) { + } catch (VaultConnectorException e) { fail("Failed to register App-ID: " + e.getMessage()); } @@ -186,8 +198,7 @@ public class HTTPVaultConnectorTest { try { boolean res = connector.registerUserId(APP_ID, USER_ID); assertThat("Failed to register App-ID", res, is(true)); - } - catch (VaultConnectorException e) { + } catch (VaultConnectorException e) { fail("Failed to register App-ID: " + e.getMessage()); } @@ -553,7 +564,7 @@ public class HTTPVaultConnectorTest { fail("Successfully read deleted secret."); } catch (VaultConnectorException e) { assertThat(e, is(instanceOf(InvalidResponseException.class))); - assertThat(((InvalidResponseException)e).getStatusCode(), is(404)); + assertThat(((InvalidResponseException) e).getStatusCode(), is(404)); } } @@ -664,21 +675,51 @@ public class HTTPVaultConnectorTest { } } + /** + * Test TLS connection with custom certificate chain. + */ + @Test + public void tlsConnectionTest() { + TokenResponse res; + try { + connector.authToken("52135869df23a5e64c5d33a9785af5edb456b8a4a235d1fe135e6fba1c35edf6"); + fail("Logged in with invalid token"); + } catch (VaultConnectorException ignored) { + } + + try { + res = connector.authToken(TOKEN_ROOT); + assertNotNull("Login failed with valid token", res); + assertThat("Login failed with valid token", connector.isAuthorized(), is(true)); + } catch (VaultConnectorException ignored) { + fail("Login failed with valid token"); + } + } + /** * Initialize Vault with resource datastore and generated configuration. - * @return Vault Configuration + * + * @param tls use TLS + * @return Vault Configuration * @throws IllegalStateException on error */ - private VaultConfiguration initializeVault() throws IllegalStateException { + private VaultConfiguration initializeVault(boolean tls) throws IllegalStateException { String dataResource = getClass().getResource("/data_dir").getPath(); /* Generate vault local unencrypted configuration */ VaultConfiguration config = new VaultConfiguration() - .withHost("127.0.0.1") + .withHost("localhost") .withPort(getFreePort()) .withDataLocation(dataResource) .disableMlock(); + /* Enable TLS with custom certificate and key, if required */ + if (tls) { + config.enableTLS() + .withCert(getClass().getResource("/tls/server.pem").getPath()) + .withKey(getClass().getResource("/tls/server.key").getPath()); + } + /* Write configuration file */ BufferedWriter bw = null; File configFile = null; @@ -686,17 +727,14 @@ public class HTTPVaultConnectorTest { configFile = tmpDir.newFile("vault.conf"); bw = new BufferedWriter(new FileWriter(configFile)); bw.write(config.toString()); - } - catch (IOException e) { + } catch (IOException e) { e.printStackTrace(); throw new IllegalStateException("Unable to generate config file."); - } - finally { + } finally { try { if (bw != null) bw.close(); - } - catch (IOException e) { + } catch (IOException e) { e.printStackTrace(); } } @@ -719,8 +757,7 @@ public class HTTPVaultConnectorTest { /* Authenticate as valid user */ try { connector.authToken(TOKEN_ROOT); - } - catch(VaultConnectorException ignored) { + } catch (VaultConnectorException ignored) { } } @@ -730,14 +767,14 @@ public class HTTPVaultConnectorTest { private void authUser() { try { connector.authUserPass(USER_VALID, PASS_VALID); - } - catch(VaultConnectorException ignored) { + } catch (VaultConnectorException ignored) { } } /** * Find and return a free TCP port. - * @return port number + * + * @return port number */ private static Integer getFreePort() { ServerSocket socket = null; diff --git a/src/test/java/de/stklcode/jvault/connector/test/VaultConfiguration.java b/src/test/java/de/stklcode/jvault/connector/test/VaultConfiguration.java index f17186f..a2922b7 100644 --- a/src/test/java/de/stklcode/jvault/connector/test/VaultConfiguration.java +++ b/src/test/java/de/stklcode/jvault/connector/test/VaultConfiguration.java @@ -22,8 +22,8 @@ import java.nio.file.Paths; /** * Vault configuration String using builder pattern. * - * @author Stefan Kalscheuer - * @since 0.1 + * @author Stefan Kalscheuer + * @since 0.1 */ public class VaultConfiguration { private String host; @@ -31,6 +31,8 @@ public class VaultConfiguration { private boolean disableTLS; private boolean disableMlock; private Path dataLocation; + private String certFile; + private String keyFile; public VaultConfiguration() { this.disableTLS = true; @@ -52,6 +54,16 @@ public class VaultConfiguration { return this; } + public VaultConfiguration withCert(String certFile) { + this.certFile = certFile; + return this; + } + + public VaultConfiguration withKey(String keyFile) { + this.keyFile = keyFile; + return this; + } + public VaultConfiguration disableMlock() { this.disableMlock = true; return this; @@ -80,12 +92,14 @@ public class VaultConfiguration { @Override public String toString() { - return "backend \"file\" {\n" + + return "backend \"file\" {\n" + " path = \"" + dataLocation + "\"\n" + "}\n" + "listener \"tcp\" {\n" + " address = \"" + host + ":" + port + "\"\n" + ((disableTLS) ? " tls_disable = 1\n" : "") + + ((certFile != null) ? " tls_cert_file = \"" + certFile + "\"\n" : "") + + ((keyFile != null) ? " tls_key_file = \"" + keyFile + "\"\n" : "") + "}\n" + ((disableMlock) ? "disable_mlock = true" : ""); } diff --git a/src/test/resources/tls/ca.pem b/src/test/resources/tls/ca.pem new file mode 100644 index 0000000..414822a --- /dev/null +++ b/src/test/resources/tls/ca.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDfzCCAmegAwIBAgIJAIsdtmg40qeTMA0GCSqGSIb3DQEBDQUAMFYxCzAJBgNV +BAYTAkRFMQowCAYDVQQIDAEgMREwDwYDVQQKDAhzdGtsY29kZTENMAsGA1UECwwE +VGVzdDEZMBcGA1UEAwwQc3RrbGNvZGUgVGVzdCBDQTAeFw0xNjExMDYxMDM4MDda +Fw00NjEwMzAxMDM4MDdaMFYxCzAJBgNVBAYTAkRFMQowCAYDVQQIDAEgMREwDwYD +VQQKDAhzdGtsY29kZTENMAsGA1UECwwEVGVzdDEZMBcGA1UEAwwQc3RrbGNvZGUg +VGVzdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKIVAIDK++4v +mH8/V9fELi3X3Ychgz2WP+dDbXrHsIdkQnmT9sdCfZuLH/0V98XwWQAFHlSfc9GB +4NEID31y/f76AcKhuAx4aLebMBp6L4eJssahhxLoKzodFZm9WVIj6g6kXl6Auc9z +v9d+DH70PHGtf/ORqnkiuraY5hTzUK7pMrRkL/BFuZyMOtsDsaBWuImZTuf8s2aF +URLbD1cnFKn3LbeydlAipA12EXgZ1KhmY8X8BOrDRQlHTIjRjCs0kV3Jc8thi2xt +N+Yo/Zm8HqP/fmuszeID0WWgRpmE8RTg8WuoDAJAb600xKEK11qpXkUT3vHiot5N +np6HoQXm0HUCAwEAAaNQME4wHQYDVR0OBBYEFFiwMeDNFusyU90UELnglsankCkd +MB8GA1UdIwQYMBaAFFiwMeDNFusyU90UELnglsankCkdMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQENBQADggEBAEwk8fDIo1Wc3EpJKNKjsCZbaiyC8GiiYfuKQVmq +82jAacf7MUw8EgpuboDwEbDSIhCeEyM/t8mgttcT/DP0vD3qMhpkNLQcuSK0NFza +XvnoPqHMZhxerc7QBMeEKYFRjUd8iPiT3D8rYPdWq8klQnLIPyws2/uyijIXo9k3 +oiPMBUO+WAe3tLwO9EV6Ff9q5BmlVufngPT1R4wTNR6mZQ3yy8CWPOsk3CBCyleT +8maCnFjhJ9fBz74WVgAO7QE72VTwsu9MZ+DawsHt8oKaNU1dfIXfqMHKh3KItn1N +cIIlhpnIUtxoWEawH6NbtCoQpTRBSZ8EoBhP4z9jC2+A7i0= +-----END CERTIFICATE----- diff --git a/src/test/resources/tls/client.key b/src/test/resources/tls/client.key new file mode 100644 index 0000000..c04e4c8 --- /dev/null +++ b/src/test/resources/tls/client.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAs+l54Lm03sacNzjlj5V2gUJPJvDQsAKi/O313vbsv4FLxFX8 +QnGYFKouFAtVW4MTpEN6ciFP6ucwb6YxtoOKIxZ4nqmMDz4R3Q2Spep7Q9I9kISX +LMvs92qE1phSqhi6dfH+ZTTPl9HlpWmSWhDReBqfSK1QPJVB1QUrmZA4yCxSfpD6 +sx0R28sPLuzR/lTiPB2aFst6aM9wG8ZMrl7KYO37W6QH/0p3CfvPdB42b8q5txTG +l9Ia++eTcZE69ESyA9LLaPWLfjzGCCW/FbF/zd3WvV8oH7IXqrOfW532Sy6Ui2Id +8DmtoNHTulFFKypDe5sF0aFWpkoJsqvaDj/I9wIDAQABAoIBAHXCDBQbeVeXiAhd +JWSl37sbO9OxK+cI0sXau2QFG1D9wCnyXfrffzuHaEGWaXhMgz6xLCQnybdnOzzY ++xELaA8vViQDtbkEV4zopWQT5jquEb3WC1023RPUlL4hVXogVWt9yZVUy8wDhtyO +DU0GVRTX2Aop5qrAxyY3DCKnU4Mw5pZW6tVrALh2W+c/7tlB3mp89uzgRVLsOyP1 +KoCiIWkb83DT73rTTYg2NOL+69Pp0idtADEE8tuo/3pgcZhAVI9jtisnWg7MsSWu +rKkNCS3vOcxAKG9kw3znJfVVH7ZF1LaDVx9LP4inEwVQfg9aImhkjquIgGT0iDgK +e62Zx4ECgYEA2YWsXSjRFrscataSM+w71tH4GlE0FAJx5FW+F4YeTfnn+k7FaXuE +562737GqsadOXkNiVVgfxsB6snR2WWjxJKuPHGJWncl7yR/MdRmradQGsQYe/xTa +AMouZIHp7BWPV/TG6s3x2ezx2GvMhGUnJ43QvTipuJFSDFObgROvz+MCgYEA07yn +4PnKXmnIZbhXz9wkvmDpbfPcCrapFmtRXBTK7fbwEA+YPl3xPjkvDX8cQDTsze7h +R+o0jMG0VPwmjfECHva5GWemcN5AFMPfuGqik0jacXa81oti0H5L67Z/ffeFxYnD +UXukXFInDLT0c8/k1Ex4shwfjiaat030olweBt0CgYEAu5+6ogx/9bxlcZ4tM84z +e0NXXtPmONA3Dv4KXl4YK6hAuT5St36MkA3iPLwSAPTP+yziV70Qg64o517fapXD +Up8MbS5Big5t0Hi2Mdd3bGwvbWhbOijxNbcvNxB8BmA+aV7AaW5Ei3X+0W+CVDyv +/kUr5NtIQeRPQkSnoDmr74MCgYEAyrnqksEXPWZS9PGXQfEpTQ5E8X12xNs28bw2 +3c8arNSt7PLBdZVEkar2nhmB1wfVYybAk7ZuMgaUvnneADEtMrBPcT+IYLCq8jbI +US3oEtTCMbjZ/SDfr3f9AOZvExCXCBdq5u1W5P3TXZs0Il5+XbYKKZ47qELWB4Og +IoPITBECgYBvA3+4YL006l/Hkyf21aDiqh3kUAhuPVSXd5ef9EvE2fxMR225jTks +URCwYxi/Njg5B2FtuXZjq/eqis/piNtqr3nwZcpiOiwr8J/jwwBXPbtIcE5Nxjzx +ag6bkbXe6mpxvHDtroAw84sC0h77ztyJ4Lq/khiEjq+XTPn1iEJ+DQ== +-----END RSA PRIVATE KEY----- diff --git a/src/test/resources/tls/client.pem b/src/test/resources/tls/client.pem new file mode 100644 index 0000000..3ff9bc1 --- /dev/null +++ b/src/test/resources/tls/client.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDVzCCAj8CCQDn4qCNgPQBezANBgkqhkiG9w0BAQ0FADBWMQswCQYDVQQGEwJE +RTEKMAgGA1UECAwBIDERMA8GA1UECgwIc3RrbGNvZGUxDTALBgNVBAsMBFRlc3Qx +GTAXBgNVBAMMEHN0a2xjb2RlIFRlc3QgQ0EwHhcNMTYxMTA2MTA0MTQ4WhcNNDEx +MDMxMTA0MTQ4WjCBhDELMAkGA1UEBhMCREUxCjAIBgNVBAgMASAxETAPBgNVBAoM +CHN0a2xjb2RlMQ0wCwYDVQQLDARUZXN0MSMwIQYDVQQDDBpzdGtsY29kZSBWYXVs +dCBUZXN0IENsaWVudDEiMCAGCSqGSIb3DQEJARYTbm9yZXBseUBzdGtsY29kZS5k +ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALPpeeC5tN7GnDc45Y+V +doFCTybw0LACovzt9d727L+BS8RV/EJxmBSqLhQLVVuDE6RDenIhT+rnMG+mMbaD +iiMWeJ6pjA8+Ed0NkqXqe0PSPZCElyzL7PdqhNaYUqoYunXx/mU0z5fR5aVpkloQ +0Xgan0itUDyVQdUFK5mQOMgsUn6Q+rMdEdvLDy7s0f5U4jwdmhbLemjPcBvGTK5e +ymDt+1ukB/9Kdwn7z3QeNm/KubcUxpfSGvvnk3GROvREsgPSy2j1i348xgglvxWx +f83d1r1fKB+yF6qzn1ud9ksulItiHfA5raDR07pRRSsqQ3ubBdGhVqZKCbKr2g4/ +yPcCAwEAATANBgkqhkiG9w0BAQ0FAAOCAQEAaW0XEGs8PpHV9dfDD3QERoDpuqsj +IkTSO6+e1Ah/Uak6nDPSkAHwS53Avz2SElM3kGa9DVniXOVxC9OjM/E74vncv71w +/MLiIS3aXbTgiUmDhuTutBrL9Q3HJGOfO6gqEyQakPfW1NFUFleJKvWKNX0S4eeZ +2nXt7da7xaxR6r0L6nwRrWT85ys/jdDgfF0SnmQRmddQttsmRCJ3DXq0z2EeXbO3 +J8XFF+Y+SyV0CB7bjHx0BXZPaISUMAqnifRqDyw/4G/9iLqFN2Lc0Lxp74w6D/8z +OSiHwFvjG1dwEkwnPL9V5vD4/BgeClre4FWqD6wqS3UwLdq6DzEaSNKHJw== +-----END CERTIFICATE----- diff --git a/src/test/resources/tls/server.key b/src/test/resources/tls/server.key new file mode 100644 index 0000000..9c00223 --- /dev/null +++ b/src/test/resources/tls/server.key @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/src/test/resources/tls/server.pem b/src/test/resources/tls/server.pem new file mode 100644 index 0000000..9fa2bb6 --- /dev/null +++ b/src/test/resources/tls/server.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEMTCCAxkCCQDn4qCNgPQBejANBgkqhkiG9w0BAQ0FADBWMQswCQYDVQQGEwJE +RTEKMAgGA1UECAwBIDERMA8GA1UECgwIc3RrbGNvZGUxDTALBgNVBAsMBFRlc3Qx +GTAXBgNVBAMMEHN0a2xjb2RlIFRlc3QgQ0EwHhcNMTYxMTA2MTAzODQxWhcNNDEx +MDMxMTAzODQxWjBfMQswCQYDVQQGEwJERTEKMAgGA1UECAwBIDERMA8GA1UECgwI +c3RrbGNvZGUxHTAbBgNVBAsMFFZhdWx0IENvbm5lY3RvciBUZXN0MRIwEAYDVQQD +DAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDdYi03 +DOzMPj+iTe7J2U5rtYKms5fj7gu6LwSxxHh3trFa/fUDxWnwbLEBKLUzIIjEx6V0 +P+4LOHgQie+7GF8UevQGNiocyPiRJ/y7lCjhvufoDYqt+JUf2qyjPUK+XihwtEYo +fQmpxY5FwoVVaECFIMqN27XdySBDFRYLiU1HOMh8yUgXwEsdOK9k79FNxUGWb+6S +lXEbxp5pLIPS8aeiKqGSrov0rw1FDsfrmXAAse1h44GMR0gnFsweL4boiabh47zy +md4LtMiyE9hIQyYiGlhiFcgyHI3ZXfX8RHuA6zhv5J3KYieNFEfzNNghMirXBypu +1MhZWqhiotgCSIvMVUmAQOE4loJOhS/xJTb5uSOFL3p7SH/TWyFw0oE007XPuD+A +obTLDBOBKKMAQ1DFblWZhXmfshPJkXSYZHfl0+zMsb64SkVO33n35Yr9WABSh5iT +mBuvTbmGcPUwwHJeRFQyeTafxjiSxnTzd22jJ4SmDHOBP6RIC8NyObXH/sakCpSv +l0ponGYRQp+WT7LuzCFEl+nwoOC+tbwyEqwewAQ7Kcjex6Gepvj1Vkp9jA+Cz2AY +INUudLTkJE4/Lew+BgSH83Xc8x1mrxQ5wQ2dPJ7c2UCXedfHR+brAPB1VyVVCrw/ +iaoZWkeZXQQlw2b1W1WiFFlGA9gPt+NNW/mdVwIDAQABMA0GCSqGSIb3DQEBDQUA +A4IBAQA4nrZlyoN/iyRDWZqudXyedMRVUquekzvkcPndInAaW2ukOl+LMGdN7C5n +wjglyg5DV0aDNy+Mpy/rInC4kZ5UDKfHjYg4Q9x6kdZOch9gJ6Qvq7hhP8hLUcta +pi/m3+k+PP/X6V1oSLxTl/Ja6peDvK1eo5imAbyEPz0kQNHZ88BxEAWGaQgNbItM +SC7xmrO78o832d07KF8fJL+o35KV0EuHKMnvr2TLv09kL61EKRRiEMxb6x/90Jw8 +Rys/FnZh+N0Xdk8sfpq6itGnaDqZSBw0EPhBDXcX9bNpztm8JIIZv101H208BfYG +GyJ1DYEp2FfyLgVcY9hNi6P0tmzn +-----END CERTIFICATE-----