summaryrefslogtreecommitdiff
path: root/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslContextBuilder.java
diff options
context:
space:
mode:
Diffstat (limited to 'eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslContextBuilder.java')
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslContextBuilder.java433
1 files changed, 433 insertions, 0 deletions
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.
+ *
+ * <p>This implementation fix an incompatibility between {@link BouncyCastleJsseProvider} and JAVA JDK >= v9</p>
+ *
+ * @author tlenz
+ *
+ */
+public class EaafSslContextBuilder {
+
+ static final String TLS = "TLS";
+
+ private String protocol;
+ private final Set<KeyManager> keyManagers;
+ private String keyManagerFactoryAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
+ private String keyStoreType = KeyStore.getDefaultType();
+ private final Set<TrustManager> 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 <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext">Java
+ * Cryptography Architecture Standard Algorithm Name
+ * Documentation</a> for more information.
+ * @return this builder
+ * @see <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext">Java
+ * Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * @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 <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext">Java
+ * Cryptography Architecture Standard Algorithm Name
+ * Documentation</a> for more information.
+ * @return this builder
+ * @see <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext">Java
+ * Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * @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
+ * <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyStore">Java
+ * Cryptography Architecture Standard Algorithm Name
+ * Documentation</a> for more information.
+ * @return this builder
+ * @see <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyStore">Java
+ * Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * @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 <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyManagerFactory">Java
+ * Cryptography Architecture Standard
+ * Algorithm Name Documentation</a> for more
+ * information.
+ * @return this builder
+ * @see <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyManagerFactory">Java
+ * Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * @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
+ * <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#TrustManagerFactory">Java
+ * Cryptography Architecture Standard
+ * Algorithm Name Documentation</a> for more
+ * information.
+ * @return this builder
+ * @see <a href=
+ * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#TrustManagerFactory">Java
+ * Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * @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<KeyManager> keyManagers,
+ final Collection<TrustManager> 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<String, PrivateKeyDetails> getClientAliasMap(
+ final String[] keyTypes, final Principal[] issuers) {
+ final Map<String, PrivateKeyDetails> 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<String, PrivateKeyDetails> getServerAliasMap(
+ final String keyType, final Principal[] issuers) {
+ final Map<String, PrivateKeyDetails> 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<String, PrivateKeyDetails> 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<String, PrivateKeyDetails> 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<String, PrivateKeyDetails> 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<String, PrivateKeyDetails> 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 + "]";
+ }
+}