From a849dd49daf60128db79311293d7f5c466bd0642 Mon Sep 17 00:00:00 2001
From: Thomas <>
Date: Fri, 16 Apr 2021 22:08:42 +0200
Subject: Use custom SSLContext builder to generate BouncyCastle specific
TrustManager in case of keys base on HSM-Facade, because SSLContext based on
BCJSSE needs BCJSSE TrustManager BCJSSE is not compatible to SunJSSE
TrustManager in Java >= 9
---
.../eaaf/core/impl/http/EaafSslContextBuilder.java | 433 +++++++++++++++++++++
.../at/gv/egiz/eaaf/core/impl/http/HttpUtils.java | 22 +-
.../test/http/HttpClientFactoryProdHostTest.java | 98 +++++
.../eaaf/core/test/http/HttpClientFactoryTest.java | 96 +++++
.../test/resources/data/hsm_ee-RSA_rootcert.crt | 3 +
.../src/test/resources/data/hsm_ee_eecert.crt | 3 +
.../src/test/resources/data/hsm_ee_rootcert.crt | 3 +
.../src/test/resources/data/server_host.crt | 18 +
.../src/test/resources/data/ssL_truststore.jks | Bin 0 -> 799 bytes
.../src/test/resources/data/ssl_host.jks | Bin 0 -> 2081 bytes
10 files changed, 664 insertions(+), 12 deletions(-)
create mode 100644 eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslContextBuilder.java
create mode 100644 eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryProdHostTest.java
create mode 100644 eaaf_core_utils/src/test/resources/data/hsm_ee-RSA_rootcert.crt
create mode 100644 eaaf_core_utils/src/test/resources/data/hsm_ee_eecert.crt
create mode 100644 eaaf_core_utils/src/test/resources/data/hsm_ee_rootcert.crt
create mode 100644 eaaf_core_utils/src/test/resources/data/server_host.crt
create mode 100644 eaaf_core_utils/src/test/resources/data/ssL_truststore.jks
create mode 100644 eaaf_core_utils/src/test/resources/data/ssl_host.jks
(limited to 'eaaf_core_utils/src')
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslContextBuilder.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslContextBuilder.java
new file mode 100644
index 00000000..1cd739de
--- /dev/null
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslContextBuilder.java
@@ -0,0 +1,433 @@
+package at.gv.egiz.eaaf.core.impl.http;
+
+import java.net.Socket;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.apache.http.ssl.PrivateKeyDetails;
+import org.apache.http.ssl.PrivateKeyStrategy;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.apache.http.ssl.TrustStrategy;
+import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
+
+/**
+ * Fork of {@link SSLContextBuilder} that uses JSSE provider to get TrustManager.
+ *
+ *
This implementation fix an incompatibility between {@link BouncyCastleJsseProvider} and JAVA JDK >= v9
+ *
+ * @author tlenz
+ *
+ */
+public class EaafSslContextBuilder {
+
+ static final String TLS = "TLS";
+
+ private String protocol;
+ private final Set keyManagers;
+ private String keyManagerFactoryAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
+ private String keyStoreType = KeyStore.getDefaultType();
+ private final Set trustManagers;
+ private String trustManagerFactoryAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
+ private SecureRandom secureRandom;
+ private Provider provider;
+
+ public static EaafSslContextBuilder create() {
+ return new EaafSslContextBuilder();
+ }
+
+ /**
+ * Get a new SSLContext builder object.
+ */
+ public EaafSslContextBuilder() {
+ super();
+ this.keyManagers = new LinkedHashSet<>();
+ this.trustManagers = new LinkedHashSet<>();
+ }
+
+ /**
+ * Sets the SSLContext protocol algorithm name.
+ *
+ * @param protocol the SSLContext protocol algorithm name of the requested
+ * protocol. See the SSLContext section in the Java
+ * Cryptography Architecture Standard Algorithm Name
+ * Documentation for more information.
+ * @return this builder
+ * @see Java
+ * Cryptography Architecture Standard Algorithm Name Documentation
+ * @deprecated Use {@link #setProtocol(String)}.
+ */
+ @Deprecated
+ public EaafSslContextBuilder useProtocol(final String protocol) {
+ this.protocol = protocol;
+ return this;
+ }
+
+ /**
+ * Sets the SSLContext protocol algorithm name.
+ *
+ * @param protocol the SSLContext protocol algorithm name of the requested
+ * protocol. See the SSLContext section in the Java
+ * Cryptography Architecture Standard Algorithm Name
+ * Documentation for more information.
+ * @return this builder
+ * @see Java
+ * Cryptography Architecture Standard Algorithm Name Documentation
+ * @since 4.4.7
+ */
+ public EaafSslContextBuilder setProtocol(final String protocol) {
+ this.protocol = protocol;
+ return this;
+ }
+
+ public EaafSslContextBuilder setSecureRandom(final SecureRandom secureRandom) {
+ this.secureRandom = secureRandom;
+ return this;
+ }
+
+ public EaafSslContextBuilder setProvider(final Provider provider) {
+ this.provider = provider;
+ return this;
+ }
+
+ public EaafSslContextBuilder setProvider(final String name) {
+ this.provider = Security.getProvider(name);
+ return this;
+ }
+
+ /**
+ * Sets the key store type.
+ *
+ * @param keyStoreType the SSLkey store type. See the KeyStore section in the
+ * Java
+ * Cryptography Architecture Standard Algorithm Name
+ * Documentation for more information.
+ * @return this builder
+ * @see Java
+ * Cryptography Architecture Standard Algorithm Name Documentation
+ * @since 4.4.7
+ */
+ public EaafSslContextBuilder setKeyStoreType(final String keyStoreType) {
+ this.keyStoreType = keyStoreType;
+ return this;
+ }
+
+ /**
+ * Sets the key manager factory algorithm name.
+ *
+ * @param keyManagerFactoryAlgorithm the key manager factory algorithm name of
+ * the requested protocol. See the
+ * KeyManagerFactory section in the Java
+ * Cryptography Architecture Standard
+ * Algorithm Name Documentation for more
+ * information.
+ * @return this builder
+ * @see Java
+ * Cryptography Architecture Standard Algorithm Name Documentation
+ * @since 4.4.7
+ */
+ public EaafSslContextBuilder setKeyManagerFactoryAlgorithm(final String keyManagerFactoryAlgorithm) {
+ this.keyManagerFactoryAlgorithm = keyManagerFactoryAlgorithm;
+ return this;
+ }
+
+ /**
+ * Sets the trust manager factory algorithm name.
+ *
+ * @param trustManagerFactoryAlgorithm the trust manager algorithm name of the
+ * requested protocol. See the
+ * TrustManagerFactory section in the
+ * Java
+ * Cryptography Architecture Standard
+ * Algorithm Name Documentation for more
+ * information.
+ * @return this builder
+ * @see Java
+ * Cryptography Architecture Standard Algorithm Name Documentation
+ * @since 4.4.7
+ */
+ public EaafSslContextBuilder setTrustManagerFactoryAlgorithm(final String trustManagerFactoryAlgorithm) {
+ this.trustManagerFactoryAlgorithm = trustManagerFactoryAlgorithm;
+ return this;
+ }
+
+ /**
+ * Load custom truststore.
+ *
+ * @param truststore {@link KeyStore} if trusted certificates
+ * @param trustStrategy Trust validation strategy
+ * @return {@link EaafSslContextBuilder}
+ * @throws NoSuchAlgorithmException In case of an invalid TrustManager algorithm
+ * @throws KeyStoreException In case of an invalid KeyStore
+ */
+ public EaafSslContextBuilder loadTrustMaterial(
+ final KeyStore truststore,
+ final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException {
+
+ final String alg = trustManagerFactoryAlgorithm == null
+ ? TrustManagerFactory.getDefaultAlgorithm()
+ : trustManagerFactoryAlgorithm;
+
+ final TrustManagerFactory tmfactory = provider != null
+ ? TrustManagerFactory.getInstance(alg, provider)
+ : TrustManagerFactory.getInstance(alg);
+ tmfactory.init(truststore);
+ final TrustManager[] tms = tmfactory.getTrustManagers();
+ if (tms != null) {
+ if (trustStrategy != null) {
+ for (int i = 0; i < tms.length; i++) {
+ final TrustManager tm = tms[i];
+ if (tm instanceof X509TrustManager) {
+ tms[i] = new TrustManagerDelegate((X509TrustManager) tm, trustStrategy);
+ }
+ }
+ }
+ Collections.addAll(this.trustManagers, tms);
+ }
+ return this;
+ }
+
+ public EaafSslContextBuilder loadTrustMaterial(
+ final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException {
+ return loadTrustMaterial(null, trustStrategy);
+ }
+
+
+ /**
+ * Load SSL client-authentication key-material into SSL context.
+ *
+ * @param keystore {@link KeyStore} for SSL client-authentication
+ * @param keyPassword Password for this keystore
+ * @param aliasStrategy Stategy to select keys by alias
+ * @return {@link EaafSslContextBuilder}
+ * @throws NoSuchAlgorithmException In case of an invalid KeyManagerFactory algorithm
+ * @throws KeyStoreException In case of an invalid KeyStore
+ * @throws UnrecoverableKeyException In case of a invalid Key in this KeyStore
+ */
+ public EaafSslContextBuilder loadKeyMaterial(
+ final KeyStore keystore,
+ final char[] keyPassword,
+ final PrivateKeyStrategy aliasStrategy)
+ throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
+ final KeyManagerFactory kmfactory = KeyManagerFactory
+ .getInstance(keyManagerFactoryAlgorithm == null ? KeyManagerFactory.getDefaultAlgorithm()
+ : keyManagerFactoryAlgorithm);
+ kmfactory.init(keystore, keyPassword);
+ final KeyManager[] kms = kmfactory.getKeyManagers();
+ if (kms != null) {
+ if (aliasStrategy != null) {
+ for (int i = 0; i < kms.length; i++) {
+ final KeyManager km = kms[i];
+ if (km instanceof X509ExtendedKeyManager) {
+ kms[i] = new KeyManagerDelegate((X509ExtendedKeyManager) km, aliasStrategy);
+ }
+ }
+ }
+ Collections.addAll(keyManagers, kms);
+ }
+ return this;
+ }
+
+ public EaafSslContextBuilder loadKeyMaterial(
+ final KeyStore keystore,
+ final char[] keyPassword) throws NoSuchAlgorithmException, KeyStoreException,
+ UnrecoverableKeyException {
+ return loadKeyMaterial(keystore, keyPassword, null);
+ }
+
+ protected void initSslContext(
+ final SSLContext sslContext,
+ final Collection keyManagers,
+ final Collection trustManagers,
+ final SecureRandom secureRandom) throws KeyManagementException {
+ sslContext.init(
+ !keyManagers.isEmpty() ? keyManagers.toArray(new KeyManager[keyManagers.size()]) : null,
+ !trustManagers.isEmpty() ? trustManagers.toArray(new TrustManager[trustManagers.size()]) : null,
+ secureRandom);
+ }
+
+ /**
+ * Build a {@link SSLContext} from this builder.
+ *
+ * @return new {@link SSLContext}
+ * @throws NoSuchAlgorithmException In case of an unknown SSL protocol
+ * @throws KeyManagementException In case of a key-access error
+ */
+ public SSLContext build() throws NoSuchAlgorithmException, KeyManagementException {
+ final SSLContext sslContext;
+ final String protocolStr = this.protocol != null ? this.protocol : TLS;
+ if (this.provider != null) {
+ sslContext = SSLContext.getInstance(protocolStr, this.provider);
+ } else {
+ sslContext = SSLContext.getInstance(protocolStr);
+ }
+ initSslContext(sslContext, keyManagers, trustManagers, secureRandom);
+ return sslContext;
+ }
+
+ static class TrustManagerDelegate implements X509TrustManager {
+
+ private final X509TrustManager trustManager;
+ private final TrustStrategy trustStrategy;
+
+ TrustManagerDelegate(final X509TrustManager trustManager, final TrustStrategy trustStrategy) {
+ super();
+ this.trustManager = trustManager;
+ this.trustStrategy = trustStrategy;
+ }
+
+ @Override
+ public void checkClientTrusted(
+ final X509Certificate[] chain, final String authType) throws CertificateException {
+ this.trustManager.checkClientTrusted(chain, authType);
+ }
+
+ @Override
+ public void checkServerTrusted(
+ final X509Certificate[] chain, final String authType) throws CertificateException {
+ if (!this.trustStrategy.isTrusted(chain, authType)) {
+ this.trustManager.checkServerTrusted(chain, authType);
+ }
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return this.trustManager.getAcceptedIssuers();
+ }
+
+ }
+
+ static class KeyManagerDelegate extends X509ExtendedKeyManager {
+
+ private final X509ExtendedKeyManager keyManager;
+ private final PrivateKeyStrategy aliasStrategy;
+
+ KeyManagerDelegate(final X509ExtendedKeyManager keyManager, final PrivateKeyStrategy aliasStrategy) {
+ super();
+ this.keyManager = keyManager;
+ this.aliasStrategy = aliasStrategy;
+ }
+
+ @Override
+ public String[] getClientAliases(
+ final String keyType, final Principal[] issuers) {
+ return this.keyManager.getClientAliases(keyType, issuers);
+ }
+
+ public Map getClientAliasMap(
+ final String[] keyTypes, final Principal[] issuers) {
+ final Map validAliases = new HashMap<>();
+ for (final String keyType : keyTypes) {
+ final String[] aliases = this.keyManager.getClientAliases(keyType, issuers);
+ if (aliases != null) {
+ for (final String alias : aliases) {
+ validAliases.put(alias,
+ new PrivateKeyDetails(keyType, this.keyManager.getCertificateChain(alias)));
+ }
+ }
+ }
+ return validAliases;
+ }
+
+ public Map getServerAliasMap(
+ final String keyType, final Principal[] issuers) {
+ final Map validAliases = new HashMap<>();
+ final String[] aliases = this.keyManager.getServerAliases(keyType, issuers);
+ if (aliases != null) {
+ for (final String alias : aliases) {
+ validAliases.put(alias,
+ new PrivateKeyDetails(keyType, this.keyManager.getCertificateChain(alias)));
+ }
+ }
+ return validAliases;
+ }
+
+ @Override
+ public String chooseClientAlias(
+ final String[] keyTypes, final Principal[] issuers, final Socket socket) {
+ final Map validAliases = getClientAliasMap(keyTypes, issuers);
+ return this.aliasStrategy.chooseAlias(validAliases, socket);
+ }
+
+ @Override
+ public String[] getServerAliases(
+ final String keyType, final Principal[] issuers) {
+ return this.keyManager.getServerAliases(keyType, issuers);
+ }
+
+ @Override
+ public String chooseServerAlias(
+ final String keyType, final Principal[] issuers, final Socket socket) {
+ final Map validAliases = getServerAliasMap(keyType, issuers);
+ return this.aliasStrategy.chooseAlias(validAliases, socket);
+ }
+
+ @Override
+ public X509Certificate[] getCertificateChain(final String alias) {
+ return this.keyManager.getCertificateChain(alias);
+ }
+
+ @Override
+ public PrivateKey getPrivateKey(final String alias) {
+ return this.keyManager.getPrivateKey(alias);
+ }
+
+ @Override
+ public String chooseEngineClientAlias(
+ final String[] keyTypes, final Principal[] issuers, final SSLEngine sslEngine) {
+ final Map validAliases = getClientAliasMap(keyTypes, issuers);
+ return this.aliasStrategy.chooseAlias(validAliases, null);
+ }
+
+ @Override
+ public String chooseEngineServerAlias(
+ final String keyType, final Principal[] issuers, final SSLEngine sslEngine) {
+ final Map validAliases = getServerAliasMap(keyType, issuers);
+ return this.aliasStrategy.chooseAlias(validAliases, null);
+ }
+
+ }
+
+ @Override
+ public String toString() {
+ return "[provider=" + provider + ", protocol=" + protocol + ", keyStoreType=" + keyStoreType
+ + ", keyManagerFactoryAlgorithm=" + keyManagerFactoryAlgorithm + ", keyManagers=" + keyManagers
+ + ", trustManagerFactoryAlgorithm=" + trustManagerFactoryAlgorithm + ", trustManagers="
+ + trustManagers
+ + ", secureRandom=" + secureRandom + "]";
+ }
+}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpUtils.java
index 365e969d..3058c9b5 100644
--- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpUtils.java
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpUtils.java
@@ -40,8 +40,6 @@ import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.conn.ssl.TrustAllStrategy;
import org.apache.http.entity.ContentType;
-import org.apache.http.ssl.SSLContextBuilder;
-import org.apache.http.ssl.SSLContexts;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;
import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
@@ -56,7 +54,6 @@ import lombok.extern.slf4j.Slf4j;
public class HttpUtils {
private static final String ERROR_03 = "internal.httpclient.03";
-
/**
* Simple Http response-handler that only give http status-code as result.
@@ -174,7 +171,7 @@ public class HttpUtils {
* @param url URL
* @param paramname Name of the parameter.
* @param paramvalue Value of the parameter.
- * @return
+ * @return Url with parameter
*/
public static String addUrlParameter(final String url, final String paramname,
final String paramvalue) {
@@ -210,7 +207,7 @@ public class HttpUtils {
boolean trustAllServerCertificates, @Nonnull String friendlyName)
throws EaafConfigurationException, EaafFactoryException {
try {
- SSLContextBuilder sslContextBuilder = SSLContexts.custom();
+ EaafSslContextBuilder sslContextBuilder = EaafSslContextBuilder.create();
injectKeyStore(sslContextBuilder, keyStore, keyAlias, keyPasswordString, friendlyName);
@@ -251,7 +248,7 @@ public class HttpUtils {
@Nonnull String friendlyName)
throws EaafConfigurationException, EaafFactoryException {
try {
- SSLContextBuilder sslContextBuilder = SSLContexts.custom();
+ EaafSslContextBuilder sslContextBuilder = EaafSslContextBuilder.create();
injectKeyStore(sslContextBuilder, keyStore, keyAlias, keyPasswordString, friendlyName);
@@ -266,7 +263,7 @@ public class HttpUtils {
}
}
- private static void injectTrustStore(SSLContextBuilder sslContextBuilder,
+ private static void injectTrustStore(EaafSslContextBuilder sslContextBuilder,
Pair trustStore, boolean trustAllServerCertificates, String friendlyName)
throws NoSuchAlgorithmException, KeyStoreException {
@@ -276,7 +273,7 @@ public class HttpUtils {
trustStrategy = new TrustAllStrategy();
}
-
+
KeyStore trustStoreImpl = null;
if (trustStore != null) {
log.info("Http-client: {} uses custom TrustStore.", friendlyName);
@@ -288,16 +285,18 @@ public class HttpUtils {
}
- private static void injectKeyStore(SSLContextBuilder sslContextBuilder, Pair keyStore,
+ private static void injectKeyStore(EaafSslContextBuilder sslContextBuilder, Pair keyStore,
String keyAlias, String keyPasswordString, String friendlyName)
throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {
+
+ Provider provider;
if (keyStore.getSecond() != null) {
- Provider provider = new BouncyCastleJsseProvider(keyStore.getSecond());
+ provider = new BouncyCastleJsseProvider(keyStore.getSecond());
log.debug("KeyStore: {} provide special security-provider. Inject: {} into SSLContext",
friendlyName, provider.getName());
sslContextBuilder.setProvider(provider);
- }
+ }
log.trace("Open SSL Client-Auth keystore with password: {}", keyPasswordString);
final char[] keyPassword = keyPasswordString == null ? StringUtils.EMPTY.toCharArray()
@@ -313,5 +312,4 @@ public class HttpUtils {
}
}
-
}
diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryProdHostTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryProdHostTest.java
new file mode 100644
index 00000000..55c17ee8
--- /dev/null
+++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryProdHostTest.java
@@ -0,0 +1,98 @@
+package at.gv.egiz.eaaf.core.test.http;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.Base64;
+
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.annotation.DirtiesContext.MethodMode;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
+import at.gv.egiz.eaaf.core.impl.http.HttpClientConfiguration;
+import at.gv.egiz.eaaf.core.impl.http.IHttpClientFactory;
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration("/spring/test_eaaf_pvp_not_lazy.beans.xml")
+@DirtiesContext
+public class HttpClientFactoryProdHostTest {
+
+ @Autowired private IHttpClientFactory httpClientFactory;
+ @Autowired private EaafKeyStoreFactory keyStoreFactory;
+
+ /**
+ * Initialize full class.
+ */
+ @BeforeClass
+ public static void classInitializer() {
+ final Logger logger = (Logger) LoggerFactory.getLogger("org.bouncycastle.jsse");
+ logger.setLevel(Level.TRACE);
+
+ }
+
+ /**
+ * JUnit test set-up.
+ *
+ */
+ @Before
+ public void setup() {
+
+ }
+
+ @Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+ public void getCustomClientX509AuthWithHsmFacadeTrustStore() throws EaafException, ClientProtocolException,
+ IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException,
+ CertificateEncodingException {
+ System.setProperty("javax.net.debug", "ssl:handshake");
+
+ final HttpClientConfiguration clientConfig = new HttpClientConfiguration("jUnit-client");
+ clientConfig.setAuthMode("ssl");
+ //clientConfig.buildKeyStoreConfig("hsmfacade", null, null, "eid-junit");
+ //clientConfig.setSslKeyAlias("rsa-key-1");
+ clientConfig.buildKeyStoreConfig("hsmfacade", null, null, "authhandler");
+ clientConfig.setSslKeyAlias("authhandler-sign");
+ clientConfig.setDisableTlsHostCertificateValidation(false);
+
+ final CloseableHttpClient client = httpClientFactory.getHttpClient(clientConfig);
+ Assert.assertNotNull("httpClient", client);
+
+ final Pair sslClientKeyStore =
+ keyStoreFactory.buildNewKeyStore(clientConfig.getKeyStoreConfig());
+ final X509Certificate clientRootCert = (X509Certificate) sslClientKeyStore.getFirst()
+ .getCertificateChain(clientConfig.getSslKeyAlias())[1];
+ final X509Certificate clientEeCert = (X509Certificate) sslClientKeyStore.getFirst()
+ .getCertificateChain(clientConfig.getSslKeyAlias())[0];
+ Base64.getEncoder().encodeToString(clientEeCert.getEncoded());
+
+ //perform test request
+ final HttpUriRequest httpGet2 = new HttpGet("https://apps.egiz.gv.at//sslclientcertdemo/");
+ final CloseableHttpResponse httpResp2 = client.execute(httpGet2);
+ Assert.assertEquals("http statusCode", 200, httpResp2.getStatusLine().getStatusCode());
+
+ }
+
+}
diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryTest.java
index baedadc8..c71d8352 100644
--- a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryTest.java
+++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/test/http/HttpClientFactoryTest.java
@@ -5,9 +5,14 @@ import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.SocketTimeoutException;
+import java.security.Key;
+import java.security.KeyPair;
import java.security.KeyStore;
import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
import java.security.Provider;
+import java.security.UnrecoverableKeyException;
import java.security.cert.X509Certificate;
import org.apache.commons.lang3.RandomStringUtils;
@@ -20,10 +25,13 @@ import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.MethodMode;
@@ -32,12 +40,16 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import at.gv.egiz.eaaf.core.exceptions.EaafException;
import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory;
+import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration;
+import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType;
import at.gv.egiz.eaaf.core.impl.data.Pair;
import at.gv.egiz.eaaf.core.impl.data.Triple;
import at.gv.egiz.eaaf.core.impl.http.HttpClientConfiguration;
import at.gv.egiz.eaaf.core.impl.http.HttpUtils;
import at.gv.egiz.eaaf.core.impl.http.IHttpClientFactory;
import at.gv.egiz.eaaf.core.impl.utils.StreamUtils;
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
import okhttp3.HttpUrl;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
@@ -57,6 +69,27 @@ public class HttpClientFactoryTest {
private MockWebServer mockWebServer = null;
private HttpUrl mockServerUrl;
+ /**
+ * Initialize full class.
+ */
+ @BeforeClass
+ public static void classInitializer() {
+ final Logger logger = (Logger) LoggerFactory.getLogger("org.bouncycastle.jsse");
+ logger.setLevel(Level.TRACE);
+
+ }
+
+ /**
+ * Reset test environment.
+ */
+ @AfterClass
+ public static void classReset() {
+ System.clearProperty("javax.net.ssl.trustStoreType");
+ System.clearProperty("javax.net.ssl.trustStore");
+ System.clearProperty("javax.net.ssl.trustStorePassword");
+
+ }
+
/**
* JUnit test set-up.
*
@@ -595,4 +628,67 @@ public class HttpClientFactoryTest {
}
+ @Test
+ @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+ public void getCustomClientX509AuthWithHsmFacadeTrustStore() throws EaafException, ClientProtocolException,
+ IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException {
+
+ final String current = new java.io.File(".").getCanonicalPath();
+ System.setProperty("javax.net.ssl.trustStoreType", "jks");
+ System.setProperty("javax.net.ssl.trustStore",
+ current + "/src/test/resources/data/ssL_truststore.jks");
+ System.setProperty("javax.net.ssl.trustStorePassword",
+ "password");
+
+ final KeyStoreConfiguration sslServerCertConfig = new KeyStoreConfiguration();
+ sslServerCertConfig.setKeyStoreType(KeyStoreType.JKS);
+ sslServerCertConfig.setFriendlyName("SSL host cert");
+ sslServerCertConfig.setSoftKeyStoreFilePath("src/test/resources/data/ssl_host.jks");
+ sslServerCertConfig.setSoftKeyStorePassword("password");
+
+ Pair sslServerHostKeyStore =
+ keyStoreFactory.buildNewKeyStore(sslServerCertConfig);
+
+
+ final HttpClientConfiguration clientConfig = new HttpClientConfiguration("jUnit-client");
+ clientConfig.setAuthMode("ssl");
+ clientConfig.buildKeyStoreConfig("hsmfacade", null, null, "authhandler");
+ clientConfig.setSslKeyAlias("authhandler-sign");
+ clientConfig.setDisableTlsHostCertificateValidation(false);
+
+ final CloseableHttpClient client = httpClientFactory.getHttpClient(clientConfig);
+ Assert.assertNotNull("httpClient", client);
+
+ //set-up mock-up web-server with SSL client authentication
+ final Pair sslClientKeyStore =
+ keyStoreFactory.buildNewKeyStore(clientConfig.getKeyStoreConfig());
+ final X509Certificate clientRootCert = (X509Certificate) sslClientKeyStore.getFirst()
+ .getCertificateChain(clientConfig.getSslKeyAlias())[1];
+ final X509Certificate clientEeCert = (X509Certificate) sslClientKeyStore.getFirst()
+ .getCertificateChain(clientConfig.getSslKeyAlias())[0];
+
+ Key sslKey = sslServerHostKeyStore.getFirst().getKey("ssl", "password".toCharArray());
+ X509Certificate sslCert = (X509Certificate) sslServerHostKeyStore.getFirst().getCertificate("ssl");
+ KeyPair keyPair = new KeyPair(sslCert.getPublicKey(), (PrivateKey) sslKey);
+ HeldCertificate localhostCertificate = new HeldCertificate(keyPair, sslCert);
+ final HandshakeCertificates serverCertificates = new HandshakeCertificates.Builder()
+ .addTrustedCertificate(clientEeCert)
+ .addTrustedCertificate(clientRootCert)
+ .heldCertificate(localhostCertificate)
+ .build();
+ mockWebServer = new MockWebServer();
+
+ mockWebServer.useHttps(serverCertificates.sslSocketFactory(), false);
+ mockWebServer.requireClientAuth();
+ mockWebServer.enqueue(new MockResponse().setResponseCode(200)
+ .setBody("Successful auth!"));
+ mockServerUrl = mockWebServer.url("/sp/junit");
+
+ //perform test request
+ final HttpUriRequest httpGet2 = new HttpGet(mockServerUrl.url().toString());
+ final CloseableHttpResponse httpResp2 = client.execute(httpGet2);
+ Assert.assertEquals("http statusCode", 200, httpResp2.getStatusLine().getStatusCode());
+
+ }
+
}
diff --git a/eaaf_core_utils/src/test/resources/data/hsm_ee-RSA_rootcert.crt b/eaaf_core_utils/src/test/resources/data/hsm_ee-RSA_rootcert.crt
new file mode 100644
index 00000000..aa83c8d9
--- /dev/null
+++ b/eaaf_core_utils/src/test/resources/data/hsm_ee-RSA_rootcert.crt
@@ -0,0 +1,3 @@
+-----BEGIN CERTIFICATE-----
+MIICDTCCAbOgAwIBAgIIVLxIFI8kRpkwCgYIKoZIzj0EAwIwEjEQMA4GA1UEAwwHRUMtUm9vdDAeFw0yMDA2MTgwNzM2MTBaFw0yNTA2MTgwNzM2MTBaMDwxGzAZBgNVBAMMEmludC1yc2Eta2V5LTEtMDAwMTERMA8GA1UECgwIc29mdHdhcmUxCjAIBgNVBAUTATEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDrM1ocQqtch95Dm21JHi0V35nlWZibsjLqR+g8ERdD1qFgun/X0I/Rbft+KxB8QsDX7UmIjXGdavNcEjY/XcbiJxUcpv7vn/2+x3JxZO6Iye/ut001okICt3OGIqP93ZEnIaTTNhDsK7OnvD/eUjlmuHiTaFq1dZLKYDQlz9jl/9F4axfrz1V7oo60iqFIW+7tlUeh8VGDUPjQpHghzjHXTJv/OIAt752K31Tn8KR3kvkn6WTPo8eOWVaPQ480Dik0e2afTPPJNZJ7BW111IwqBAOKp586yVsQ4XVEF8H64Cq+s+b4/HBboo9TDJKTJvo2yQmcTsahbH+Rlm20ifUTAgMBAAEwCgYIKoZIzj0EAwIDSAAwRQIhANKN/N2Atb5fbeHSB2Myv/JcNf9JonxFe92AOu4f62NNAiBjOEeg4OyJZKPiDl6aqYVtz1Qroo6xzUC9UVA4qNe4LA==
+-----END CERTIFICATE-----
diff --git a/eaaf_core_utils/src/test/resources/data/hsm_ee_eecert.crt b/eaaf_core_utils/src/test/resources/data/hsm_ee_eecert.crt
new file mode 100644
index 00000000..b4c47c78
--- /dev/null
+++ b/eaaf_core_utils/src/test/resources/data/hsm_ee_eecert.crt
@@ -0,0 +1,3 @@
+-----BEGIN CERTIFICATE-----
+MIIDEzCCArqgAwIBAgIIMrAOP6EqywMwCgYIKoZIzj0EAwIwEjEQMA4GA1UEAwwHRUMtUm9vdDAeFw0yMDA2MTgwNzM2MDlaFw0yNTA2MTgwNzM2MDlaMEMxIjAgBgNVBAMMGWludC1hdXRoaGFuZGxlci1zaWduLTAwMDExETAPBgNVBAoMCHNvZnR3YXJlMQowCAYDVQQFEwExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA5j2vR8ZV88fOJzFHmLuPizHXk+aiE0fX8Bu63FqCNa2Vy343u2k+4HVQBWpAtyRej8nL7JQuhFa11YRtVF+Vos9cyUDk482sUlYA2LdAFIuHJP6iTRrrHYdiTskc3FQUm9m9KorVFwnfzqJ40wjn9hD0xKCE0odk9IHA5aLTul0mSMcHQ+MMu2cbelK2TWTEC0wcGum2NrTWukhf0E4/e4SuqMgEUPdHSEaNZLGKZU0kyVtXKK0HCtWF8OKGay4V504dk3qnmRHHO8ik3oyPk2yLipQAPL0bUGMZ7tlRLo5VxJvkZSsJfAzvYn1JzcQIt6bXszQGU/JS6dw7Jq99Ckzox/vk8p1YUPd4tCuUJPXzhFhI7CedHKGItwk7mQf5llgeVJy40sVrFwHLDPufY5mlm9C+gVBs71+ibT/sJ96gCueWqduzDX8fHzeaNVj2NFEx2pT46D5cbRWZBow3+Rx+hpge6SDMzaebpbkgLPX+35D952bMLjm+9T0DulGk1tLL2k4YK+1WWUprlo+rm65OA5FxnO5YxNmGk2Uizu3tSoZMxmXwEWoFfYaMsTt5Not3+CLPjfs6pE4ML9ifAOxW+pPsmanDiNaMiL0/aSddvvkv3lSMRiU9nYh3DuOu6sGIMaPdyYF0V/9Fua2SDZV3QKIbzPbJfEsXFKtjtzUCAwEAATAKBggqhkjOPQQDAgNHADBEAiBHsK819KfxVn91KAmjRjb7zx8TLLBApyaZHXi5HVrYUwIgQbF6u6bXziAWdijlJC0IOWdBuTLWmTvFqBH7uX1HL9c=
+-----END CERTIFICATE-----
diff --git a/eaaf_core_utils/src/test/resources/data/hsm_ee_rootcert.crt b/eaaf_core_utils/src/test/resources/data/hsm_ee_rootcert.crt
new file mode 100644
index 00000000..fa7b132f
--- /dev/null
+++ b/eaaf_core_utils/src/test/resources/data/hsm_ee_rootcert.crt
@@ -0,0 +1,3 @@
+-----BEGIN CERTIFICATE-----
+MIIBPDCB46ADAgECAghZ0/gtbA6FrjAKBggqhkjOPQQDAjASMRAwDgYDVQQDDAdFQy1Sb290MB4XDTIwMDYxODA3MzU1M1oXDTMwMDYxODA3MzU1M1owEjEQMA4GA1UEAwwHRUMtUm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABIjgL+6qiE9oj2yWCkVm6s7AaYkbDhTptYXTW92MhASiTqxL6g8tr28MlRA2P8HPrNSK9payeMe5QW9Kxn+EMPejIzAhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgWgMAoGCCqGSM49BAMCA0gAMEUCIDq2f4xjYD8pzr+mdzuT8wzePRnj/EatjmimGnvNt3FjAiEArezudh6G+wE+ds6S0dnFxG0o/BrbR0fiRNTQwiZA9ec=
+-----END CERTIFICATE-----
diff --git a/eaaf_core_utils/src/test/resources/data/server_host.crt b/eaaf_core_utils/src/test/resources/data/server_host.crt
new file mode 100644
index 00000000..21d3a1e4
--- /dev/null
+++ b/eaaf_core_utils/src/test/resources/data/server_host.crt
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC2TCCAcECBGB5WpEwDQYJKoZIhvcNAQELBQAwMTELMAkGA1UEBhMCQVQxDjAM
+BgNVBAsMBWpVbml0MRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMjEwNDE2MDkzNjE3
+WhcNMjQwMTEwMDkzNjE3WjAxMQswCQYDVQQGEwJBVDEOMAwGA1UECwwFalVuaXQx
+EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAJVYLzPzq7oBGS5Wer0++rHbp+DWI7srAV1lGHdq8ST6APh/7fEVWpdZDpMY
+bOXl6uIiVmMsx/jUhQwOu4rFXThiQlwyQOv57SO7WHqNPqbRs/EUVnzW35aXU/DB
+CmkqKyjK/+vuq7tIahlpqrppCzBVC9/Z15U+RMTdnATrohALNJovydH3VSkdkKX0
+5BDx779/8malTgyWTUgl+p3F/91iIIl4ZvIngo2ZYQCFm1nV6jmpErGFkG6YVrO7
+oe3OlGKFiXtqCmq+NSFeXsv/SaXWNUw82pYKuK/5EFSLX49HLBBDI14eOCuVLnGA
+H/kG3tGteYMBNzSMmC/kcKgRDnUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAAJn2
+a/VbtXGmHe9wmtu8K3noyECfG5fbu9URUjXhCBlXGcdjfz1gzrOHcmaBndk0a566
+R2W0fLvjLpjWChrj7r34EpNYGPMLV2gp3ZkiSGl9kv8mf9iChK6+ga3SlyHJuXXu
+gw6eOIAxBrE/vLw+pZtCEV9yPrIydkt19jjejf1wjs5y2G7m5r5pBIh6Wlmmc4f2
+3M6l6Dge78WVdUaU5AeAHjgGgXwULxmLGxi6yiS5HsSeb79oGz9psHbq1EAvwOVY
+sLepTbDQvX/VAAG7HOJXhdGM0fRIkM7HFA5+6joTHvAKhuMlFIJ8Y4QIG2QaIBAh
+eBBh91x/aB2xOKs+Kg==
+-----END CERTIFICATE-----
diff --git a/eaaf_core_utils/src/test/resources/data/ssL_truststore.jks b/eaaf_core_utils/src/test/resources/data/ssL_truststore.jks
new file mode 100644
index 00000000..4d7bc2f3
Binary files /dev/null and b/eaaf_core_utils/src/test/resources/data/ssL_truststore.jks differ
diff --git a/eaaf_core_utils/src/test/resources/data/ssl_host.jks b/eaaf_core_utils/src/test/resources/data/ssl_host.jks
new file mode 100644
index 00000000..4ca07595
Binary files /dev/null and b/eaaf_core_utils/src/test/resources/data/ssl_host.jks differ
--
cgit v1.2.3