From 13ed9bf8a7264c61671646d95d73ce0d20cd04d8 Mon Sep 17 00:00:00 2001 From: Jay Zhu Date: Sat, 6 Dec 2014 21:06:47 -0800 Subject: [PATCH] Add Unit Test and Integration Test for SSL support feature This commit added UT and IT to cover the SSL support featre. Namely: * Introduced RestAssured as the client to simplify the testing code * Create a set of PKI and CA for testing different combinations of keystore and turststore in local environment * Added UT to cover HttpsSettings, WireMockConfiguration and CommandLineOptions class * Added IT to cover the case where WireMock server quires client auth --- build.gradle | 1 + .../wiremock/common/HttpsSettings.java | 46 +-- .../wiremock/core/WireMockConfiguration.java | 43 ++- .../wiremock/jetty6/Jetty6HttpServer.java | 11 +- .../standalone/CommandLineOptions.java | 22 +- .../wiremock/HttpsAcceptanceTest.java | 204 +++++++--- .../wiremock/common/HttpsSettingsTest.java | 21 ++ .../core/WireMockConfigurationTest.java | 41 ++ .../standalone/CommandLineOptionsTest.java | 40 +- src/test/resources/bad-keystore | 0 src/test/resources/stores/bad-keystore.jks | 1 + src/test/resources/stores/ca/README.md | 10 + .../resources/stores/ca/certs/ca.cert.pem | 32 ++ .../stores/ca/certs/localhost.cert.pem | 28 ++ src/test/resources/stores/ca/index.txt | 2 + src/test/resources/stores/ca/index.txt.attr | 1 + .../resources/stores/ca/index.txt.attr.old | 1 + src/test/resources/stores/ca/index.txt.old | 1 + .../resources/stores/ca/newcerts/1000.pem | 28 ++ .../resources/stores/ca/newcerts/1001.pem | 28 ++ src/test/resources/stores/ca/openssl.cnf | 350 ++++++++++++++++++ .../resources/stores/ca/private/ca.key.pem | 54 +++ src/test/resources/stores/ca/serial | 1 + src/test/resources/stores/ca/serial.old | 1 + src/test/resources/stores/test-keystore.jks | Bin 0 -> 5437 bytes src/test/resources/stores/test-truststore.jks | Bin 0 -> 1480 bytes src/test/resources/test-keystore | Bin 1376 -> 0 bytes 27 files changed, 856 insertions(+), 111 deletions(-) create mode 100644 src/test/java/com/github/tomakehurst/wiremock/common/HttpsSettingsTest.java create mode 100644 src/test/java/com/github/tomakehurst/wiremock/core/WireMockConfigurationTest.java delete mode 100644 src/test/resources/bad-keystore create mode 100644 src/test/resources/stores/bad-keystore.jks create mode 100644 src/test/resources/stores/ca/README.md create mode 100644 src/test/resources/stores/ca/certs/ca.cert.pem create mode 100644 src/test/resources/stores/ca/certs/localhost.cert.pem create mode 100644 src/test/resources/stores/ca/index.txt create mode 100644 src/test/resources/stores/ca/index.txt.attr create mode 100644 src/test/resources/stores/ca/index.txt.attr.old create mode 100644 src/test/resources/stores/ca/index.txt.old create mode 100644 src/test/resources/stores/ca/newcerts/1000.pem create mode 100644 src/test/resources/stores/ca/newcerts/1001.pem create mode 100644 src/test/resources/stores/ca/openssl.cnf create mode 100644 src/test/resources/stores/ca/private/ca.key.pem create mode 100644 src/test/resources/stores/ca/serial create mode 100644 src/test/resources/stores/ca/serial.old create mode 100644 src/test/resources/stores/test-keystore.jks create mode 100644 src/test/resources/stores/test-truststore.jks delete mode 100644 src/test/resources/test-keystore diff --git a/build.gradle b/build.gradle index 8f28838825..ecd26abd0f 100644 --- a/build.gradle +++ b/build.gradle @@ -44,6 +44,7 @@ dependencies { exclude group: "org.hamcrest", module: "hamcrest-core" exclude group: "org.hamcrest", module: "hamcrest-library" } + testCompile "com.jayway.restassured:rest-assured:2.4.0" testCompile "net.sf.json-lib:json-lib:2.4:jdk15" testCompile "com.googlecode.jarjar:jarjar:1.3" testCompile "commons-io:commons-io:2.4" diff --git a/src/main/java/com/github/tomakehurst/wiremock/common/HttpsSettings.java b/src/main/java/com/github/tomakehurst/wiremock/common/HttpsSettings.java index 150b4b390a..5abf32351c 100644 --- a/src/main/java/com/github/tomakehurst/wiremock/common/HttpsSettings.java +++ b/src/main/java/com/github/tomakehurst/wiremock/common/HttpsSettings.java @@ -18,24 +18,24 @@ public class HttpsSettings { private final int port; - private final String keyStorePath; - private final String keyStorePassword; - private final String trustStorePath; - private final String trustStorePassword; + private final String keystore; + private final String keyPassword; + private final String truststore; + private final String trustPassword; private final boolean needClientAuth; - public HttpsSettings(int port, String keyStorePath, String keyStorePassword, String trustStorePath, String trustStorePassword, boolean needClientAuth) { + public HttpsSettings(int port, String keystore, String keyPassword, String truststore, String trustPassword, boolean needClientAuth) { this.port = port; - this.keyStorePath = keyStorePath; - this.keyStorePassword = keyStorePassword; - this.trustStorePath = trustStorePath; - this.trustStorePassword = trustStorePassword; + this.keystore = keystore; + this.keyPassword = keyPassword; + this.truststore = truststore; + this.trustPassword = trustPassword; this.needClientAuth = needClientAuth; } - public HttpsSettings(int port, String keyStorePath, String keyStorePassword) { - this(port, keyStorePath, keyStorePassword, null, null, false); + public HttpsSettings(int port, String keystore, String keyPassword) { + this(port, keystore, keyPassword, null, null, false); } public static final HttpsSettings NO_HTTPS = new HttpsSettings(0, null, null); @@ -44,24 +44,24 @@ public int port() { return port; } - public String keyStorePath() { - return keyStorePath; + public String keystore() { + return keystore; } public boolean enabled() { return this != NO_HTTPS; } - public String getKeyStorePassword() { - return keyStorePassword; + public String keyPassword() { + return keyPassword; } - public String getTrustStorePath() { - return trustStorePath; + public String truststore() { + return truststore; } - public String getTrustStorePassword() { - return trustStorePassword; + public String trustPassword() { + return trustPassword; } public boolean needClientAuth() { @@ -72,10 +72,10 @@ public boolean needClientAuth() { public String toString() { return "HttpsSettings{" + "port=" + port + - ", keyStorePath='" + keyStorePath + '\'' + - ", keyStorePassword='" + keyStorePassword + '\'' + - ", trustStorePath='" + trustStorePath + '\'' + - ", trustStorePassword='" + trustStorePassword + '\'' + + ", keystore='" + keystore + '\'' + + ", keyPassword='" + keyPassword + '\'' + + ", truststore='" + truststore + '\'' + + ", trustPassword='" + trustPassword + '\'' + ", needClientAuth=" + needClientAuth + '}'; } diff --git a/src/main/java/com/github/tomakehurst/wiremock/core/WireMockConfiguration.java b/src/main/java/com/github/tomakehurst/wiremock/core/WireMockConfiguration.java index c7f2d4d735..dc3619cae2 100644 --- a/src/main/java/com/github/tomakehurst/wiremock/core/WireMockConfiguration.java +++ b/src/main/java/com/github/tomakehurst/wiremock/core/WireMockConfiguration.java @@ -18,6 +18,7 @@ import com.github.tomakehurst.wiremock.common.*; import com.github.tomakehurst.wiremock.http.CaseInsensitiveKey; import com.google.common.io.Resources; +import org.apache.commons.lang.StringUtils; import java.util.List; @@ -59,23 +60,23 @@ public WireMockConfiguration httpsPort(Integer httpsPort) { return this; } - public WireMockConfiguration keystorePath(String path) { - this.keyStorePath = path; + public WireMockConfiguration keystore(String keystore) { + this.keyStorePath = keystore; return this; } - public WireMockConfiguration keystorePass(String path) { - this.keyStorePassword = path; + public WireMockConfiguration keyPassword(String password) { + this.keyStorePassword = password; return this; } - public WireMockConfiguration truststorePath(String path) { - this.trustStorePath = path; + public WireMockConfiguration truststore(String truststore) { + this.trustStorePath = truststore; return this; } - public WireMockConfiguration truststorePass(String path) { - this.trustStorePassword = path; + public WireMockConfiguration trustPassword(String password) { + this.trustStorePassword = password; return this; } @@ -164,11 +165,31 @@ public HttpsSettings httpsSettings() { return HttpsSettings.NO_HTTPS; } - if (keyStorePath == null) { - return new HttpsSettings(httpsPort, Resources.getResource("keystore").toString(), "password"); + final String keyStorePath; + if (StringUtils.isEmpty(this.keyStorePath)) { + keyStorePath = Resources.getResource("keystore").toString(); + } else { + keyStorePath = this.keyStorePath; } - return new HttpsSettings(httpsPort, keyStorePath, keyStorePassword, trustStorePath, trustStorePassword, needClientAuth); + + final String keyStorePassword; + if (StringUtils.isEmpty(this.keyStorePassword)) { + keyStorePassword = "password"; + } else { + keyStorePassword = this.keyStorePassword; + } + + if (StringUtils.isEmpty(keyStorePath)) { + throw new IllegalArgumentException("Try to enable HTTPS port but missing a valid Keystore. " + + "Please either specify a valid keystore path, " + + "or put the keystore in resource with name 'keystore'"); + } + + return new HttpsSettings(httpsPort, + keyStorePath, keyStorePassword, + trustStorePath, trustStorePassword, + needClientAuth); } @Override diff --git a/src/main/java/com/github/tomakehurst/wiremock/jetty6/Jetty6HttpServer.java b/src/main/java/com/github/tomakehurst/wiremock/jetty6/Jetty6HttpServer.java index c6fb50dc32..a051732f81 100644 --- a/src/main/java/com/github/tomakehurst/wiremock/jetty6/Jetty6HttpServer.java +++ b/src/main/java/com/github/tomakehurst/wiremock/jetty6/Jetty6HttpServer.java @@ -54,7 +54,6 @@ class Jetty6HttpServer implements HttpServer { StubRequestHandler stubRequestHandler, RequestDelayControl requestDelayControl ) { - jettyServer = new Server(); httpConnector = createHttpConnector( requestDelayControl, @@ -138,12 +137,12 @@ private DelayableSslSocketConnector createHttpsConnector( connector.setHost(bindAddress); connector.setPort(httpsSettings.port()); connector.setHeaderBufferSize(8192); - connector.setKeystore(httpsSettings.keyStorePath()); - connector.setKeyPassword(httpsSettings.getKeyStorePassword()); + connector.setKeystore(httpsSettings.keystore()); + connector.setKeyPassword(httpsSettings.keyPassword()); - connector.setTruststore(httpsSettings.getTrustStorePath()); - if (httpsSettings.getTrustStorePassword() != null) { - connector.setTrustPassword(httpsSettings.getTrustStorePassword()); + connector.setTruststore(httpsSettings.truststore()); + if (httpsSettings.trustPassword() != null) { + connector.setTrustPassword(httpsSettings.trustPassword()); } connector.setNeedClientAuth(httpsSettings.needClientAuth()); diff --git a/src/main/java/com/github/tomakehurst/wiremock/standalone/CommandLineOptions.java b/src/main/java/com/github/tomakehurst/wiremock/standalone/CommandLineOptions.java index 532e2b7b8b..9cf5bc7e89 100644 --- a/src/main/java/com/github/tomakehurst/wiremock/standalone/CommandLineOptions.java +++ b/src/main/java/com/github/tomakehurst/wiremock/standalone/CommandLineOptions.java @@ -27,6 +27,7 @@ import com.google.common.io.Resources; import joptsimple.OptionParser; import joptsimple.OptionSet; +import org.apache.commons.lang.StringUtils; import java.io.IOException; import java.io.StringWriter; @@ -158,16 +159,19 @@ public HttpsSettings httpsSettings() { return HttpsSettings.NO_HTTPS; } - if (optionSet.has(HTTPS_KEYSTORE)) { - return new HttpsSettings(httpsPortNumber(), - (String) optionSet.valueOf(HTTPS_KEYSTORE), - (String) optionSet.valueOf(HTTPS_KEYSTORE_PASS), - (String) optionSet.valueOf(HTTPS_TRUSTSTORE), - (String) optionSet.valueOf(HTTPS_TRUSTSTORE_PASS), - Boolean.valueOf( (String) optionSet.valueOf(HTTPS_NEED_CLIENT_AUTH))); + final String keyStorePath = optionSet.has(HTTPS_KEYSTORE) ? (String) optionSet.valueOf(HTTPS_KEYSTORE) : Resources.getResource("keystore").toString(); + final String keyStorePassword = optionSet.has(HTTPS_KEYSTORE_PASS) ? (String) optionSet.valueOf(HTTPS_KEYSTORE_PASS) : "password"; + + if (StringUtils.isEmpty(keyStorePath)) { + throw new IllegalArgumentException("Try to enable HTTPS port but missing a valid Keystore. " + + "Please either specify keystore path with --https-keystore argument, " + + "or put the keystore in resource with name 'keystore'"); } - return new HttpsSettings(httpsPortNumber(), Resources.getResource("keystore").toString(), "password"); + return new HttpsSettings(httpsPortNumber(), keyStorePath, keyStorePassword, + (String) optionSet.valueOf(HTTPS_TRUSTSTORE), + (String) optionSet.valueOf(HTTPS_TRUSTSTORE_PASS), + Boolean.valueOf((String) optionSet.valueOf(HTTPS_NEED_CLIENT_AUTH))); } private int httpsPortNumber() { @@ -238,7 +242,7 @@ public String toString() { if (httpsSettings().enabled()) { builder.put(HTTPS_PORT, nullToString(httpsSettings().port())) - .put(HTTPS_KEYSTORE, nullToString(httpsSettings().keyStorePath())); + .put(HTTPS_KEYSTORE, nullToString(httpsSettings().keystore())); } if (!(proxyVia() == NO_PROXY)) { diff --git a/src/test/java/com/github/tomakehurst/wiremock/HttpsAcceptanceTest.java b/src/test/java/com/github/tomakehurst/wiremock/HttpsAcceptanceTest.java index c1edb63d01..5e7657c573 100644 --- a/src/test/java/com/github/tomakehurst/wiremock/HttpsAcceptanceTest.java +++ b/src/test/java/com/github/tomakehurst/wiremock/HttpsAcceptanceTest.java @@ -16,136 +16,220 @@ package com.github.tomakehurst.wiremock; import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.common.FatalStartupException; import com.github.tomakehurst.wiremock.core.WireMockConfiguration; import com.github.tomakehurst.wiremock.http.Fault; -import com.github.tomakehurst.wiremock.http.HttpClientFactory; import com.google.common.io.Resources; -import org.apache.http.HttpResponse; +import com.jayway.restassured.RestAssured; +import org.apache.commons.lang.exception.ExceptionUtils; import org.apache.http.MalformedChunkCodingException; import org.apache.http.NoHttpResponseException; import org.apache.http.ProtocolException; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.util.EntityUtils; +import org.apache.http.conn.ssl.SSLContexts; +import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.junit.After; +import org.junit.Before; import org.junit.Test; +import javax.net.ssl.*; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; + import static com.github.tomakehurst.wiremock.client.WireMock.*; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; -import static junit.framework.Assert.assertTrue; -import static org.hamcrest.Matchers.instanceOf; +import static com.jayway.restassured.config.SSLConfig.sslConfig; import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; public class HttpsAcceptanceTest { private static final int HTTPS_PORT = 8443; - private WireMockServer wireMockServer; - private HttpClient httpClient; - private void startServerWithKeystore(String keystorePath) { - WireMockConfiguration config = wireMockConfig().httpsPort(HTTPS_PORT); - if (keystorePath != null) { - config.keystorePath(keystorePath); - } + private void startServerWithSSL(int port, + String keystorePath, String keystorePassword, + String truststorePath, String truststorePassword, + boolean needsClientAuth) { + WireMockConfiguration config = wireMockConfig().httpsPort(port) + .keystore(keystorePath) + .keyPassword(keystorePassword) + .truststore(truststorePath) + .trustPassword(truststorePassword) + .needClientAuth(needsClientAuth); wireMockServer = new WireMockServer(config); wireMockServer.start(); WireMock.configure(); + } + + private void startDefaultHttpsServer() { + startServerWithSSL(HTTPS_PORT, null, null, null, null, false); + } + + private void startHttpsServerWithKeystore(final String keystorePath) { + startServerWithSSL(HTTPS_PORT, keystorePath, null, null, null, false); + } + + private void startHttpsServerWithKeystore(final String keystorePath, final String keyPassword) { + startServerWithSSL(HTTPS_PORT, keystorePath, keyPassword, null, null, false); + } - httpClient = HttpClientFactory.createClient(); + private void startHttpsServerWithClientAuth(final String keystorePath, final String truststorePath) { + startServerWithSSL(HTTPS_PORT, keystorePath, "password", truststorePath, "password", true); } - private void startServerWithDefaultKeystore() { - startServerWithKeystore(null); + @Before + public void setup() { + RestAssured.baseURI = "https://localhost"; + RestAssured.port = HTTPS_PORT; + } + + /** + * trust all hosts regardless if the SSL certificate is invalid + */ + private void relaxHttpsValidation() { + RestAssured.useRelaxedHTTPSValidation(); } @After - public void serverShutdown() { + public void teardown() { wireMockServer.stop(); + RestAssured.reset(); } @Test public void shouldReturnStubOnSpecifiedPort() throws Exception { - startServerWithDefaultKeystore(); - stubFor(get(urlEqualTo("/https-test")).willReturn(aResponse().withStatus(200).withBody("HTTPS content"))); + relaxHttpsValidation(); + startDefaultHttpsServer(); - assertThat(contentFor(url("/https-test")), is("HTTPS content")); + expectGetHttpsContent(); } - @Test - public void emptyResponseFault() { - startServerWithDefaultKeystore(); + @Test(expected = NoHttpResponseException.class) + public void emptyResponseFault() throws Throwable { + relaxHttpsValidation(); + startDefaultHttpsServer(); stubFor(get(urlEqualTo("/empty/response")).willReturn( aResponse() .withFault(Fault.EMPTY_RESPONSE))); - - getAndAssertUnderlyingExceptionInstanceClass(url("/empty/response"), NoHttpResponseException.class); + getAndThrowUnderlyingException("/empty/response"); } - @Test - public void malformedResponseChunkFault() { - startServerWithDefaultKeystore(); + @Test(expected = MalformedChunkCodingException.class) + public void malformedResponseChunkFault() throws Throwable { + relaxHttpsValidation(); + startDefaultHttpsServer(); stubFor(get(urlEqualTo("/malformed/response")).willReturn( aResponse() .withFault(Fault.MALFORMED_RESPONSE_CHUNK))); - getAndAssertUnderlyingExceptionInstanceClass(url("/malformed/response"), MalformedChunkCodingException.class); + getAndThrowUnderlyingException("/malformed/response"); } - @Test - public void randomDataOnSocketFault() { - startServerWithDefaultKeystore(); + @Test(expected = ProtocolException.class) + public void randomDataOnSocketFault() throws Throwable { + relaxHttpsValidation(); + startDefaultHttpsServer(); stubFor(get(urlEqualTo("/random/data")).willReturn( aResponse() .withFault(Fault.RANDOM_DATA_THEN_CLOSE))); - getAndAssertUnderlyingExceptionInstanceClass(url("/random/data"), ProtocolException.class); + getAndThrowUnderlyingException("/random/data"); } - @Test(expected = Exception.class) + @Test(expected = FatalStartupException.class) public void throwsExceptionWhenBadAlternativeKeystore() { - String testKeystorePath = Resources.getResource("bad-keystore").toString(); - startServerWithKeystore(testKeystorePath); + String testKeystorePath = Resources.getResource("stores/bad-keystore.jks").getFile(); + startHttpsServerWithKeystore(testKeystorePath); + } + + @Test(expected = FatalStartupException.class) + public void throwsExceptionWhenKeypasswordIsWrong() { + String testKeystorePath = Resources.getResource("stores/test-keystore.jks").getFile(); + startHttpsServerWithKeystore(testKeystorePath, "wrong-pass"); } @Test public void acceptsAlternativeKeystore() throws Exception { - String testKeystorePath = Resources.getResource("test-keystore").toString(); - startServerWithKeystore(testKeystorePath); - stubFor(get(urlEqualTo("/https-test")).willReturn(aResponse().withStatus(200).withBody("HTTPS content"))); + relaxHttpsValidation(); - assertThat(contentFor(url("/https-test")), is("HTTPS content")); + String testKeystorePath = Resources.getResource("stores/test-keystore.jks").getFile(); + startHttpsServerWithKeystore(testKeystorePath); + + expectGetHttpsContent(); } - private String url(String path) { - return String.format("https://localhost:%d%s", HTTPS_PORT, path); + @Test(expected = SSLHandshakeException.class) + public void expectDenyRequestIfNotTrusted() { + String testKeystorePath = Resources.getResource("stores/test-keystore.jks").getFile(); + String testTruststorePath = Resources.getResource("stores/test-truststore.jks").getFile(); + startHttpsServerWithClientAuth(testKeystorePath, testTruststorePath); + + expectGetHttpsContent(); } - private void getAndAssertUnderlyingExceptionInstanceClass(String url, Class expectedClass) { - boolean thrown = false; + @Test + public void expectGetHttpsContentWithClientAuth() throws Exception { + String testKeystorePath = Resources.getResource("stores/test-keystore.jks").getFile(); + String testTruststorePath = Resources.getResource("stores/test-truststore.jks").getFile(); + startHttpsServerWithClientAuth(testKeystorePath, testTruststorePath); + + // Client carry certificate that the server trusts + SSLContext sslcontext = SSLContexts.custom() + .loadTrustMaterial(createKeyStore(testTruststorePath, "password"), new TrustSelfSignedStrategy()) + .loadKeyMaterial(createKeyStore(testKeystorePath, "password"), "password".toCharArray()) + .useTLS() + .build(); + + RestAssured.config = RestAssured.config().sslConfig(sslConfig().sslSocketFactory(new org.apache.http.conn.ssl.SSLSocketFactory(sslcontext))); + + expectGetHttpsContent(); + } + + private KeyStore createKeyStore(final String path, final String password) + throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException { + InputStream inputStream = null; try { - contentFor(url); + inputStream = new FileInputStream(path); + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(inputStream, password.toCharArray()); + + return keyStore; + } finally { + if (inputStream != null) { + inputStream.close(); + } + } + } + + private void expectGetHttpsContent() { + final String path = "/https-test"; + final String content = "HTTPS content"; + + stubFor(get(urlEqualTo(path)) + .willReturn(aResponse().withStatus(200).withBody(content))); + + RestAssured.expect().statusCode(200) + .when().get(path) + .then().body(is(content)); + } + + private void getAndThrowUnderlyingException(String url) throws Throwable { + try { + RestAssured.get(url).body().asString(); } catch (Exception e) { Throwable cause = e.getCause(); if (cause != null) { - assertThat(e.getCause(), instanceOf(expectedClass)); + throw ExceptionUtils.getRootCause(e); } else { - assertThat(e, instanceOf(expectedClass)); + throw e; } - - thrown = true; } - - assertTrue("No exception was thrown", thrown); - } - - private String contentFor(String url) throws Exception { - HttpGet get = new HttpGet(url); - HttpResponse response = httpClient.execute(get); - String content = EntityUtils.toString(response.getEntity()); - return content; } } diff --git a/src/test/java/com/github/tomakehurst/wiremock/common/HttpsSettingsTest.java b/src/test/java/com/github/tomakehurst/wiremock/common/HttpsSettingsTest.java new file mode 100644 index 0000000000..6ea7ae5d13 --- /dev/null +++ b/src/test/java/com/github/tomakehurst/wiremock/common/HttpsSettingsTest.java @@ -0,0 +1,21 @@ +package com.github.tomakehurst.wiremock.common; + +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +public class HttpsSettingsTest { + + @Test + public void expectHttpEnableReturnFalseForNoHttpsSettings() { + assertThat(HttpsSettings.NO_HTTPS.enabled(), equalTo(false)); + } + + @Test + public void expectHttpEnableReturnTrueForValidSettings() { + final HttpsSettings settings = new HttpsSettings(8443, "keystore_path", "keystore_password", + "truststore_path", "truststore_password", true); + assertThat(settings.enabled(), equalTo(true)); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/tomakehurst/wiremock/core/WireMockConfigurationTest.java b/src/test/java/com/github/tomakehurst/wiremock/core/WireMockConfigurationTest.java new file mode 100644 index 0000000000..46aadb8acf --- /dev/null +++ b/src/test/java/com/github/tomakehurst/wiremock/core/WireMockConfigurationTest.java @@ -0,0 +1,41 @@ +package com.github.tomakehurst.wiremock.core; + +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +public class WireMockConfigurationTest { + @Test + public void expectToSetAndGetHttpsSettings() { + final String keystorePath = "keystore-path"; + final String keystorePassword = "keystore-password"; + final String truststorePath = "truststore-path"; + final String truststorePassword = "truststore-password"; + final int httpsPort = 8443; + final boolean needClientAuth = true; + + final WireMockConfiguration configuration = new WireMockConfiguration(); + configuration.httpsPort(httpsPort); + configuration.needClientAuth(needClientAuth); + configuration.keystore(keystorePath); + configuration.keyPassword(keystorePassword); + configuration.truststore(truststorePath); + configuration.trustPassword(truststorePassword); + + + assertThat(configuration.httpsSettings().enabled(), equalTo(true)); + assertThat(configuration.httpsSettings().port(), equalTo(httpsPort)); + assertThat(configuration.httpsSettings().needClientAuth(), equalTo(needClientAuth)); + assertThat(configuration.httpsSettings().keystore(), equalTo(keystorePath)); + assertThat(configuration.httpsSettings().keyPassword(), equalTo(keystorePassword)); + assertThat(configuration.httpsSettings().truststore(), equalTo(truststorePath)); + assertThat(configuration.httpsSettings().trustPassword(), equalTo(truststorePassword)); + } + + @Test + public void expectNoHttpsByDefault() { + final WireMockConfiguration configuration = new WireMockConfiguration(); + assertThat(configuration.httpsSettings().enabled(), equalTo(false)); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/tomakehurst/wiremock/standalone/CommandLineOptionsTest.java b/src/test/java/com/github/tomakehurst/wiremock/standalone/CommandLineOptionsTest.java index c191c0bdc5..2a5cd5d707 100644 --- a/src/test/java/com/github/tomakehurst/wiremock/standalone/CommandLineOptionsTest.java +++ b/src/test/java/com/github/tomakehurst/wiremock/standalone/CommandLineOptionsTest.java @@ -71,7 +71,7 @@ public void enablesHttpsAndSetsPortNumberWhenOptionPresent() { @Test public void setsKeyStorePath() { CommandLineOptions options = new CommandLineOptions("--https-port", "8443", "--https-keystore", "/my/keystore"); - assertThat(options.httpsSettings().keyStorePath(), is("/my/keystore")); + assertThat(options.httpsSettings().keystore(), is("/my/keystore")); } @Test(expected=IllegalArgumentException.class) @@ -160,6 +160,42 @@ public void returnPreserveHostHeaderFalseWhenNotPresent() { public void preventsRecordingWhenRequestJournalDisabled() { new CommandLineOptions("--no-request-journal", "--record-mappings"); } - + @Test + public void returnKeystorePwdWhenPresent() { + final CommandLineOptions options = new CommandLineOptions("--https-port", "8443", + "--https-keystore-pass", "password"); + assertThat(options.httpsSettings().keyPassword(), is("password")); + } + + @Test + public void returnKeystorePathWhenPresent() { + final CommandLineOptions options = new CommandLineOptions("--https-port", "8443", + "--https-keystore", "keystore_path"); + assertThat(options.httpsSettings().keystore(), is("keystore_path")); + } + + @Test + public void returnTruststorePwdWhenPresent() { + final CommandLineOptions options = new CommandLineOptions("--https-port", "8443", + "--https-keystore", "keystore_path", + "--https-truststore-pass", "password"); + assertThat(options.httpsSettings().keyPassword(), is("password")); + } + + @Test + public void returnTruststorePathWhenPresent() { + final CommandLineOptions options = new CommandLineOptions("--https-port", "8443", + "--https-keystore", "keystore_path", + "--https-truststore", "truststore_path"); + assertThat(options.httpsSettings().truststore(), is("truststore_path")); + } + + @Test + public void returnNeedsClientAuthWhenPresent() { + final CommandLineOptions options = new CommandLineOptions("--https-port", "8443", + "--https-keystore", "keystore_path", + "--https-need-client-auth", "true"); + assertThat(options.httpsSettings().needClientAuth(), is(true)); + } } diff --git a/src/test/resources/bad-keystore b/src/test/resources/bad-keystore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/test/resources/stores/bad-keystore.jks b/src/test/resources/stores/bad-keystore.jks new file mode 100644 index 0000000000..efe6edf8c5 --- /dev/null +++ b/src/test/resources/stores/bad-keystore.jks @@ -0,0 +1 @@ +THIS IS AN INVALID KEYSTORE \ No newline at end of file diff --git a/src/test/resources/stores/ca/README.md b/src/test/resources/stores/ca/README.md new file mode 100644 index 0000000000..bb195f765b --- /dev/null +++ b/src/test/resources/stores/ca/README.md @@ -0,0 +1,10 @@ +# Certificate Authority for Acceptance Test + +This folder stores the CA for creating certificates that were used in HTTPS acceptance test. + +All the places where password is asked, the password is "password" + +## References +* [How to act as your own certificate authority (CA)](https://jamielinux.com/articles/2013/08/act-as-your-own-certificate-authority/) +* [How to create and sign SSL certificates when acting as a certificate authority (CA)](https://jamielinux.com/articles/2013/08/create-and-sign-ssl-certificates-certificate-authority/) +* [Common Java Keytool Commands](http://www.lmhproductions.com/37/common-java-keytool-commands/) \ No newline at end of file diff --git a/src/test/resources/stores/ca/certs/ca.cert.pem b/src/test/resources/stores/ca/certs/ca.cert.pem new file mode 100644 index 0000000000..546eea7f86 --- /dev/null +++ b/src/test/resources/stores/ca/certs/ca.cert.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFiTCCA3GgAwIBAgIJAJwAhbCaZMLiMA0GCSqGSIb3DQEBCwUAMFsxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQxFDASBgNVBAMMC1dpcmVNb2NrIENBMB4XDTE0MTIwNzAz +MTkxOVoXDTI0MTIwNDAzMTkxOVowWzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNv +bWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEUMBIG +A1UEAwwLV2lyZU1vY2sgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCZnPliMl8Kb3JrlSYfw3p5PtNCl3XasjF03339Al3JFS02ukJpff2xy4UVXQWE +JVdmf6vm4Gv+KeszPj18R01E4ayjkcEYE3Ril2wrXfHL15H2Mhb+IzfiDXjFP0HL +BEHEcyvL/+yW6ZL4ZkiJ5daAIz65sNxyHkNWfXaRecqBYrPQT9zq7UvwJnoR0XgY +JE4plp+/nF7rz/9PuKLkRmbFl6OlNKzghlhp6CJ/utqYDfJOnHorwgi1tIBwe8IG +6XPadzRpdIjTPwIdwohFeFmESUBQSproSZfDqeaSnsdoKFa5T/+6+ioYjJVJUzvz +5cfN+2LMD5hBZL5SLKVxtaz4Yw9bn84NGmOA16Zc8FW2tF79aRNmrMUOi6Zn64Qx +ffncWoBXqPoei8kBvHFpTbQG4OmeqZ+CKtV785m513j1kIqx0BYn+8LGMI6bpqGC +8iuMo5t9Q0br0evnIubGXBDf10NnK4iSXz0p+4dfGESSnohZIB0XpRg906FVhIGS +A0QnERjyXCDFHC29osi9ELXgUCSWNVwsxdghyrk30LPZrk2HR20uRZlrlbpnh5sm +3FDIzXKHcn46eQX/+LejmxQ1D9/5kzZ5b9ySywqsQ11rmWI0NmuWEVRRCEyjc/D+ +4LnAeGhwezeWbOPQxgtFJMnDXJnOOfi5u6aNWBAm7WyOxwIDAQABo1AwTjAdBgNV +HQ4EFgQUGOGjZes4ynltVnse0WbXjP+3VxcwHwYDVR0jBBgwFoAUGOGjZes4ynlt +Vnse0WbXjP+3VxcwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAlF14 +4dXOj4VhlK1ZGTyaF3MOy69t/MwAp2ekIM7BRJ/8DlMKy2jirB8/oy8mwhkpDxeg +cR2ZxfrV8Zk7cZzHl6erFDfZ4M3xcjcouWzmdbzVckzSbgZvWB6Z1MnffVOKOlEC +w/w8cHJqsm/uCM5PU/7gO64w/QemNF5mbTboxulMBTDyzF+dqTg1OdV18Hbax4wl +bJK9Habaa/l1nXi8WVroFq7jXjzR4u3srSspRMsMzIhvEgklLJZzjbPEW8P4FQVx +O7sVJKipHvlw34P668WHSsbVoyOIXfpA58eIBO5iU2Ydks6wBVpndn8mZzRVCH/d +WnqBdKqEaJAW5Hd5HZvmWBGioaRVOuADLblxl4ArQfRCUoS2h8acFhXYKD73xgQ3 +0hEZMGyRzB3akr3SRXawe/rQqtGBJKQO3EjwcuA5mIvbN+U5VOypycCkIOK1rzj1 +XFjjFHfQpQ7XfjVTYM0ymRf8Bb22m/wCO4ZQWsYOL4RLng22YwI+qMow4gaim6e3 +ef/EwDVbbi5pkhVzx8+MMblvguonwmHC5eMBYPdya+3lriyCNKTX6lp2wIXTFh4s +ruNi/rzy/3umvYEkLA2q5Wi8E58AZ32aG5DCwA08iys5I8Ykx5ZzW14zPJESrI3z +nF73CZrr0s8wcFRNtoa1e98ZjW/56mEq84fsYWs= +-----END CERTIFICATE----- diff --git a/src/test/resources/stores/ca/certs/localhost.cert.pem b/src/test/resources/stores/ca/certs/localhost.cert.pem new file mode 100644 index 0000000000..50d74a2c58 --- /dev/null +++ b/src/test/resources/stores/ca/certs/localhost.cert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIErjCCApagAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwWzELMAkGA1UEBhMCQVUx +EzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMg +UHR5IEx0ZDEUMBIGA1UEAwwLV2lyZU1vY2sgQ0EwHhcNMTQxMjA3MDQxNTI0WhcN +MTUxMjA3MDQxNTI0WjBcMRAwDgYDVQQGEwdVbmtub3duMRAwDgYDVQQIEwdVbmtu +b3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRIwEAYDVQQD +Ewlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCHMrQR +XvmYaWvplFLxRVoUfHYhXneeZGs9GYrW7V1+8x5DY9gegspqCH7UhMn4MnRVgXCP +3v3piKMw9Dh/2xG51z9io6ivWeTSb3yAJhDY+hmYPRQxW0vJXkvu3wJwgk5IepuY +vS37RaRqwUP0AEe/qUotc9qjbobpQWX/arndZFak0l4lED1efJzWXmoeJIuit3KM +snYvkOWzLxx9t6ugqQsDHPICZl/xpNoDVY0H1bNJ0HTCSDwcDej+BC26lJVHm5Zs +ynMNCWtx/tDX6Sgp7WWnWtZDmR3L4cdffQpxCIyJfgRIjhhH/ntHp+ZnC/Ts/mYn +bEms9KGWs/zlZLkpAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8W +HU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBQ5y/H6otm2 +pcyRrkHjNu2IYysw0zAfBgNVHSMEGDAWgBQY4aNl6zjKeW1Wex7RZteM/7dXFzAN +BgkqhkiG9w0BAQsFAAOCAgEALz+GtM/UloDgiOkvSxVcEbpWluR/PW4u1OyfklMF +zpy1A0eKgXzs0wKcN4j8LDd2tWV7mAe4+fcYZvz+5W+CSieQFgWxBBVuojFUWoju +b/fHlwtct3+oyJ4exDkMUfLSza+aniMQbg/Bt5WnBu0kO4COgxjrDCGi8ISzLVbz +S2yBEUOq8iKxaSiDpoy5zHgMSTK9rYj4NYrou8GnSnpTTbMQV1juTMqFy+FCMIpy +LzMVreOwBy1vtywctDjuhJaO5g101a4sW7QGVVF82BT/FCsg4AtSrNYWhFXZkBZt +uCjXl/Yf38e02111/t5dgJ1Z5K3OY5KJhctii/nM+QqrRt+RZMnddKth3tTROxQG +i5+s003reGR1a4e363NUYnFNpn1kT7LAZFisceP2Zw3/cm1utDJMK2qU4tw0N+LB +hmaQuzL2zAfX26nxvlDF41CnBez3Wp1Rov3H6zbhUrbg68AFFGjiCVyV2IxTLiBN +BCn8s5OnniveitgthMsqHz8XHiFC+YAMbLnrDbjOVY/QKHWejHyaH0LpwXtlwOjk +F9ha0Q4pgIoUTp9d4IZhV7SIk2ucuV2XeMvGQKpUvbJPqg5ecGiOICLtTM4AyKXB +PktUcqpX4fe8mr6WDK7esqZv1dRiXW1l2j58e8aZK0dYHD8ER5wHsANJOOPrIlQ/ +rIc= +-----END CERTIFICATE----- diff --git a/src/test/resources/stores/ca/index.txt b/src/test/resources/stores/ca/index.txt new file mode 100644 index 0000000000..1efd1f8918 --- /dev/null +++ b/src/test/resources/stores/ca/index.txt @@ -0,0 +1,2 @@ +V 151207032952Z 1000 unknown /C=Unknown/ST=Unknown/O=Unknown/OU=Unknown/CN=WireMock.Test.Keystore +V 151207041524Z 1001 unknown /C=Unknown/ST=Unknown/O=Unknown/OU=Unknown/CN=localhost diff --git a/src/test/resources/stores/ca/index.txt.attr b/src/test/resources/stores/ca/index.txt.attr new file mode 100644 index 0000000000..8f7e63a347 --- /dev/null +++ b/src/test/resources/stores/ca/index.txt.attr @@ -0,0 +1 @@ +unique_subject = yes diff --git a/src/test/resources/stores/ca/index.txt.attr.old b/src/test/resources/stores/ca/index.txt.attr.old new file mode 100644 index 0000000000..8f7e63a347 --- /dev/null +++ b/src/test/resources/stores/ca/index.txt.attr.old @@ -0,0 +1 @@ +unique_subject = yes diff --git a/src/test/resources/stores/ca/index.txt.old b/src/test/resources/stores/ca/index.txt.old new file mode 100644 index 0000000000..10d70f92a1 --- /dev/null +++ b/src/test/resources/stores/ca/index.txt.old @@ -0,0 +1 @@ +V 151207032952Z 1000 unknown /C=Unknown/ST=Unknown/O=Unknown/OU=Unknown/CN=WireMock.Test.Keystore diff --git a/src/test/resources/stores/ca/newcerts/1000.pem b/src/test/resources/stores/ca/newcerts/1000.pem new file mode 100644 index 0000000000..6a915a4a6a --- /dev/null +++ b/src/test/resources/stores/ca/newcerts/1000.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEuzCCAqOgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwWzELMAkGA1UEBhMCQVUx +EzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMg +UHR5IEx0ZDEUMBIGA1UEAwwLV2lyZU1vY2sgQ0EwHhcNMTQxMjA3MDMyOTUyWhcN +MTUxMjA3MDMyOTUyWjBpMRAwDgYDVQQGEwdVbmtub3duMRAwDgYDVQQIEwdVbmtu +b3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMR8wHQYDVQQD +ExZXaXJlTW9jay5UZXN0LktleXN0b3JlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAiVOjGzAmDM8jiRdztwgrW39VEuXS2X1c59k9JXpftAmZBefmbwoh +7gTBzP0TWHrINXG1aTjkkvuRtptWReHViiQA4FQgv0bLLvEdB5H5sXuGajBoYMJW +je4+I/8z5rRD0PGCOOrqI2QtVil7LoeM0qDRXMYCyvh6Ac+V4pbj4ZNFwkscvRFV +K50WS0RDE+2bs0P9UAgr0x4lMaybn9RqyTkF/lfLd9CEQcpX+G8CcGzPntx/j8XT +vvCTO3LcGj9RClt2fWM4313Bq6O8AfkN2vcTdeUTGV6Vs2ApxFsyFKsi4CSSBvpJ +yjzwhlV6BDDuYwmGCvVs0XPAXVRWXMFDyQIDAQABo3sweTAJBgNVHRMEAjAAMCwG +CWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNV +HQ4EFgQUR9Pmwqd07rYvKD5dcvVCzKwZ0r0wHwYDVR0jBBgwFoAUGOGjZes4ynlt +Vnse0WbXjP+3VxcwDQYJKoZIhvcNAQELBQADggIBAFGG/lI0pxje2Qfbg/i6DAPV +FzeGpGlyZO5IINZXE5lUaGEMG5NAE+x/MZKYkJFEFIfdWbvo14v94ZiXAnp+/K++ +GZy/g52KNJbsq5VdJYzbrIXfnEWrWcD86bBxXfM2R/AGvclVofaK31VX2caB+pu3 +PAqzyJdhyEtTCqWQ3gIvLAx8o8BSaeox+QsoTcoDU5V6+Knk2ek3RE6eemwVc46k +flUcD6yxIWJLlSjLlBe/i3jyoO4PmmtJoFmqKm1eLJ2d+g4rEVeouokkhfKun/8r +V20UCJp8P7D2Dmowq99QYpRUBDrwQkZ3oNbIkxMXMfMXRGAMoN/x4p29Gnyxg+i8 +/F4pAZj6WKi9PgMfb3tkhB2HhYUDELGTUmmGOhtiThgrhQDZfZfKTmkJdf62UNHu +DdnSQ5BtvNTvnKvcr3kX8TTpZKYVhkU1SxaRNlzd9/jh5+Hw0eBAInadfgB+DHWD +BLB8jQjcao3tljnNc+Yi4n8J8yWZHOv6RICOHIQ9eeKum0RHIDsgFQo6evcz7DSI +Q1cF6lpXlsAO/JSMCYtV8flFyuwtgjByRPvyJ2Gb+ybdqIlj8Ie65t/Rn801pClN +clAIewM0zViJy8LuJg8Sw0mJOqZb+5WKEyray7MTmUQrDb3TW9OhhyZvDbaSF1Lk +9LBvX7/fZTRFF2YcuYeN +-----END CERTIFICATE----- diff --git a/src/test/resources/stores/ca/newcerts/1001.pem b/src/test/resources/stores/ca/newcerts/1001.pem new file mode 100644 index 0000000000..50d74a2c58 --- /dev/null +++ b/src/test/resources/stores/ca/newcerts/1001.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIErjCCApagAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwWzELMAkGA1UEBhMCQVUx +EzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMg +UHR5IEx0ZDEUMBIGA1UEAwwLV2lyZU1vY2sgQ0EwHhcNMTQxMjA3MDQxNTI0WhcN +MTUxMjA3MDQxNTI0WjBcMRAwDgYDVQQGEwdVbmtub3duMRAwDgYDVQQIEwdVbmtu +b3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRIwEAYDVQQD +Ewlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCHMrQR +XvmYaWvplFLxRVoUfHYhXneeZGs9GYrW7V1+8x5DY9gegspqCH7UhMn4MnRVgXCP +3v3piKMw9Dh/2xG51z9io6ivWeTSb3yAJhDY+hmYPRQxW0vJXkvu3wJwgk5IepuY +vS37RaRqwUP0AEe/qUotc9qjbobpQWX/arndZFak0l4lED1efJzWXmoeJIuit3KM +snYvkOWzLxx9t6ugqQsDHPICZl/xpNoDVY0H1bNJ0HTCSDwcDej+BC26lJVHm5Zs +ynMNCWtx/tDX6Sgp7WWnWtZDmR3L4cdffQpxCIyJfgRIjhhH/ntHp+ZnC/Ts/mYn +bEms9KGWs/zlZLkpAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8W +HU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBQ5y/H6otm2 +pcyRrkHjNu2IYysw0zAfBgNVHSMEGDAWgBQY4aNl6zjKeW1Wex7RZteM/7dXFzAN +BgkqhkiG9w0BAQsFAAOCAgEALz+GtM/UloDgiOkvSxVcEbpWluR/PW4u1OyfklMF +zpy1A0eKgXzs0wKcN4j8LDd2tWV7mAe4+fcYZvz+5W+CSieQFgWxBBVuojFUWoju +b/fHlwtct3+oyJ4exDkMUfLSza+aniMQbg/Bt5WnBu0kO4COgxjrDCGi8ISzLVbz +S2yBEUOq8iKxaSiDpoy5zHgMSTK9rYj4NYrou8GnSnpTTbMQV1juTMqFy+FCMIpy +LzMVreOwBy1vtywctDjuhJaO5g101a4sW7QGVVF82BT/FCsg4AtSrNYWhFXZkBZt +uCjXl/Yf38e02111/t5dgJ1Z5K3OY5KJhctii/nM+QqrRt+RZMnddKth3tTROxQG +i5+s003reGR1a4e363NUYnFNpn1kT7LAZFisceP2Zw3/cm1utDJMK2qU4tw0N+LB +hmaQuzL2zAfX26nxvlDF41CnBez3Wp1Rov3H6zbhUrbg68AFFGjiCVyV2IxTLiBN +BCn8s5OnniveitgthMsqHz8XHiFC+YAMbLnrDbjOVY/QKHWejHyaH0LpwXtlwOjk +F9ha0Q4pgIoUTp9d4IZhV7SIk2ucuV2XeMvGQKpUvbJPqg5ecGiOICLtTM4AyKXB +PktUcqpX4fe8mr6WDK7esqZv1dRiXW1l2j58e8aZK0dYHD8ER5wHsANJOOPrIlQ/ +rIc= +-----END CERTIFICATE----- diff --git a/src/test/resources/stores/ca/openssl.cnf b/src/test/resources/stores/ca/openssl.cnf new file mode 100644 index 0000000000..10547dc7fb --- /dev/null +++ b/src/test/resources/stores/ca/openssl.cnf @@ -0,0 +1,350 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +# Policies used by the TSA examples. +tsa_policy1 = 1.2.3.4.1 +tsa_policy2 = 1.2.3.4.5.6 +tsa_policy3 = 1.2.3.4.5.7 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./ # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem# The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = default # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = optional +stateOrProvinceName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = AU +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Some-State + +localityName = Locality Name (eg, city) + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Internet Widgits Pty Ltd + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +#organizationalUnitName_default = + +commonName = Common Name (e.g. server FQDN or YOUR name) +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This is required for TSA certificates. +# extendedKeyUsage = critical,timeStamping + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo + +#################################################################### +[ tsa ] + +default_tsa = tsa_config1 # the default TSA section + +[ tsa_config1 ] + +# These are used by the TSA reply generation only. +dir = ./demoCA # TSA root directory +serial = $dir/tsaserial # The current serial number (mandatory) +crypto_device = builtin # OpenSSL engine to use for signing +signer_cert = $dir/tsacert.pem # The TSA signing certificate + # (optional) +certs = $dir/cacert.pem # Certificate chain to include in reply + # (optional) +signer_key = $dir/private/tsakey.pem # The TSA private key (optional) + +default_policy = tsa_policy1 # Policy if request did not specify it + # (optional) +other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) +digests = md5, sha1 # Acceptable message digests (mandatory) +accuracy = secs:1, millisecs:500, microsecs:100 # (optional) +clock_precision_digits = 0 # number of digits after dot. (optional) +ordering = yes # Is ordering defined for timestamps? + # (optional, default: no) +tsa_name = yes # Must the TSA name be included in the reply? + # (optional, default: no) +ess_cert_id_chain = no # Must the ESS cert id chain be included? + # (optional, default: no) diff --git a/src/test/resources/stores/ca/private/ca.key.pem b/src/test/resources/stores/ca/private/ca.key.pem new file mode 100644 index 0000000000..feea58b84b --- /dev/null +++ b/src/test/resources/stores/ca/private/ca.key.pem @@ -0,0 +1,54 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,FEB3D195FD4289C3DF8240311909E7BF + +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 +-----END RSA PRIVATE KEY----- diff --git a/src/test/resources/stores/ca/serial b/src/test/resources/stores/ca/serial new file mode 100644 index 0000000000..7d802a3e71 --- /dev/null +++ b/src/test/resources/stores/ca/serial @@ -0,0 +1 @@ +1002 diff --git a/src/test/resources/stores/ca/serial.old b/src/test/resources/stores/ca/serial.old new file mode 100644 index 0000000000..dd11724042 --- /dev/null +++ b/src/test/resources/stores/ca/serial.old @@ -0,0 +1 @@ +1001 diff --git a/src/test/resources/stores/test-keystore.jks b/src/test/resources/stores/test-keystore.jks new file mode 100644 index 0000000000000000000000000000000000000000..8f829a14ae4f9b5b1a82e421ba48426d20cf4e24 GIT binary patch literal 5437 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 literal 0 HcmV?d00001 diff --git a/src/test/resources/test-keystore b/src/test/resources/test-keystore deleted file mode 100644 index 398082654ca8aabf26183800c0e92eebeb9e4b2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1376 zcmezO_TO6u1_mY|W&~r7^30;t-2CKhpn%N}+iE?ax)-)}RSr^#(Gu+Ulgu&N8W^?;}tBSyj zJQ|OWWL*x?KP%yI$L{l*lZQ2QUfDLyEjP(^WtfqZms$IEsmA4SiG{^W&ZV+$|7O$1 z!aChHpiTFAN>p4rqnK2BUH!t(xwcGe&iX4_-FOlqx!vSLi^>x9BhkJ(p;s#Z=q`!X z=eN-R*Xd-ha&d*Osa55P%iC1kXWu!*raRSc!GenxO)ZU6-|tzn*7?SauvId@dsCm^ zkxgE!Ht_?K_}n0l^m+RqRn~H;v3>ZzsH9Efa>#`{7gj|vUD}>{(qvWHyyJFI{m{y6uiWBoF3F@DcG#qyHdHm=GIl8CrrcDtKf z?p1x!ulv{A9^P6w?LftH38{r99uv~|t0wn&Zp z)^7`0*9V_6a`u%?G!ok$b#jkI1G7O|%#Nd5tr-={KPM+F5C8ZhhohGB$#eJad6TV! zE=7HfP>=kE+p8IzUWH}bPc!hHGf7f*vE#Y(;55w|p=WAf2~5bb zz=RxW(8PFX0W%XL6BA3I%9~dPylk9WZ60mkd4Z{#mBFCUPym?JnL}CFgxN#$vh(uG z^I#$z7$WQ#B3u|E+z1g-17VQK%)&e&`MC;?*{K<&Ma3lsa^k#(#s)@428O1_CI&`P zV6Lf=A(T51PHLQw94^4@&fM6`V9?mf)Y!<-7=3lo?Y8s-k3Oz`eR%QTl4G~~{v^oi zKWV&pB}IF^k&)(Pzll?Q!@hkx-gGVKzykYovtNIiSFR9y%w1?*`ReeKY<~RA%Eop- zAFm8PJn_MTqoxmw)7hS$P1qOmXN%;{?<@PH%`C2Iw#aX8z0+HIRX9wNbJKeJzC#I- z^5=PjE?)~~VrFDuM0Or9+L(dvQdzoLbXL(}{wl`SH&;1kHyu@HbU!^cLt}R1i!C!w zC2qaDy0ARl^-50EH0H~UTOSq{T}uD1Qtx>){^o5phF5w*bL-4}