Skip to content

Commit 93a2933

Browse files
committed
enable custom truststore file and password
Signed-off-by: Jesse Gorzinski <[email protected]>
1 parent b934120 commit 93a2933

File tree

2 files changed

+142
-4
lines changed

2 files changed

+142
-4
lines changed

Diff for: src/main/java/com/ibm/as400/access/AS400JDBCDriver.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1191,9 +1191,9 @@ else if (clearPassword == null)
11911191
as400 = AS400.newInstance(secure, serverName, userName);
11921192
else
11931193
as400 = AS400.newInstance(secure, serverName, userName, clearPassword, additionalAuthenticationFactor);
1194-
Object sslSocketFactoryObject = jdProperties.getOriginalInfo().get(PROPERTY_SSL_SOCKET_FACTORY);
1195-
if ((sslSocketFactoryObject != null) && (sslSocketFactoryObject instanceof SSLSocketFactory)) {
1196-
as400.setSSLSocketFactory((SSLSocketFactory) sslSocketFactoryObject);
1194+
SSLSocketFactory sslSocketFactoryObject = jdProperties.getCustomSSLSocketFactory();
1195+
if (null != sslSocketFactoryObject) {
1196+
as400.setSSLSocketFactory(sslSocketFactoryObject);
11971197
}
11981198
}
11991199
catch (AS400SecurityException e)

Diff for: src/main/java/com/ibm/as400/access/JDProperties.java

+139-1
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,25 @@
1414
package com.ibm.as400.access;
1515

1616
import java.io.Serializable;
17+
import java.net.InetAddress;
18+
import java.net.Socket;
19+
import java.net.UnknownHostException;
20+
import java.security.KeyStore;
21+
import java.security.cert.CertificateException;
22+
import java.security.cert.X509Certificate;
23+
import java.io.FileInputStream;
1724
import java.io.IOException; // @W2a
1825
import java.sql.DriverPropertyInfo;
1926

2027
import java.util.Enumeration;
2128
import java.util.Properties;
2229

30+
import javax.net.ssl.SSLContext;
31+
import javax.net.ssl.SSLSocketFactory;
32+
import javax.net.ssl.TrustManagerFactory;
33+
import javax.net.ssl.TrustManager;
34+
import javax.net.ssl.X509TrustManager;
35+
2336

2437

2538
/**
@@ -181,9 +194,12 @@ public class JDProperties implements Serializable, Cloneable //@PDC 550
181194
static final int ADDITIONAL_AUTHENTICATION_FACTOR=101;
182195
static final int STAY_ALIVE = 102;
183196

197+
static final int TLS_TRUSTSTORE_FILE = 103;
198+
static final int TLS_TRUSTSTORE_FILE_PASS = 104;
199+
184200
// @W2 always add to the end of the array!
185201

186-
private static final int NUMBER_OF_ATTRIBUTES_ = 103;
202+
private static final int NUMBER_OF_ATTRIBUTES_ = 105;
187203

188204

189205
// Property names.
@@ -254,6 +270,8 @@ public class JDProperties implements Serializable, Cloneable //@PDC 550
254270
private static final String TIME_FORMAT_ = "time format";
255271
private static final String TIMESTAMP_FORMAT_ = "timestamp format";
256272
private static final String TIME_SEPARATOR_ = "time separator";
273+
private static final String TLS_TRUSTSTORE_FILE_ = "tls truststore";
274+
private static final String TLS_TRUSTSTORE_FILE_PASS_ = "tls truststore password";
257275
private static final String TRACE_ = "trace";
258276
private static final String TRACE_SERVER_ = "server trace"; // @j1a
259277
private static final String TRACE_TOOLBOX_ = "toolbox trace"; // @K1A
@@ -1652,8 +1670,22 @@ public class JDProperties implements Serializable, Cloneable //@PDC 550
16521670
dpi_[i].required = false;
16531671
dpi_[i].choices = new String[0];
16541672
defaults_[i] = "0";
1673+
1674+
i = TLS_TRUSTSTORE_FILE;
1675+
dpi_[i] = new DriverPropertyInfo (TLS_TRUSTSTORE_FILE_, "");
1676+
dpi_[i].description = "TLS_TRUSTSTORE_FILE";
1677+
dpi_[i].required = false;
1678+
dpi_[i].choices = new String[0];
1679+
defaults_[i] = EMPTY_;
16551680

16561681

1682+
i = TLS_TRUSTSTORE_FILE_PASS;
1683+
dpi_[i] = new DriverPropertyInfo (TLS_TRUSTSTORE_FILE_PASS_, "");
1684+
dpi_[i].description = "TLS_TRUSTSTORE_FILE_PASS";
1685+
dpi_[i].required = false;
1686+
dpi_[i].choices = new String[0];
1687+
defaults_[i] = EMPTY_;
1688+
16571689
}
16581690

16591691

@@ -2019,6 +2051,112 @@ String getString (int index)
20192051
return value.trim();
20202052
}
20212053

2054+
/**
2055+
* Gets a custom SSL Socket Factory, or returns <tt>null</tt> if no custom SSL Socket factory is specified
2056+
* (in which case, the system default factory will be used).
2057+
*
2058+
* The custom SSL Socket Factory is determined as follows:
2059+
* <ul>
2060+
* <li>If an {@link SSLSocketFactory} object was provided through the special property defined by
2061+
* {@link AS400JDBCDriver#PROPERTY_SSL_SOCKET_FACTORY}, all other properties are ignored and
2062+
* that object is returned.
2063+
* <li>A {@link SSLSocketFactory} will be created if both the {@value #TLS_TRUSTSTORE_FILE_} {@value #TLS_TRUSTSTORE_FILE_PASS_}
2064+
* properties were specified, indicating a JKS-format truststore file and password. Note that the special value '*ANY'
2065+
* can be used to disable all verification.
2066+
* </ul>
2067+
*/
2068+
SSLSocketFactory getCustomSSLSocketFactory() {
2069+
Properties originalProps = this.getOriginalInfo();
2070+
Object sslSocketFactoryObject = null == originalProps ? null: originalProps.get(AS400JDBCDriver.PROPERTY_SSL_SOCKET_FACTORY);
2071+
if ((sslSocketFactoryObject != null) && (sslSocketFactoryObject instanceof SSLSocketFactory)) {
2072+
return (SSLSocketFactory) sslSocketFactoryObject;
2073+
}
2074+
final String truststoreFile = getString(TLS_TRUSTSTORE_FILE);
2075+
final String truststorePass = getString(TLS_TRUSTSTORE_FILE_PASS);
2076+
if (null != truststoreFile && null != truststorePass && !truststoreFile.isEmpty()
2077+
&& !truststorePass.isEmpty()) {
2078+
return new SSLSocketFactory() {
2079+
private SSLSocketFactory sslSocketFactory_ = null;
2080+
2081+
private synchronized SSLSocketFactory getSSLSocketFactory() throws IOException {
2082+
if (null != sslSocketFactory_) {
2083+
return sslSocketFactory_;
2084+
}
2085+
if ("*ANY".equalsIgnoreCase(truststoreFile) && "*ANY".equalsIgnoreCase(truststorePass)) {
2086+
try {
2087+
SSLContext ctx = SSLContext.getInstance("TLS");
2088+
//@formatter:off
2089+
ctx.init(null, new TrustManager[] {
2090+
new X509TrustManager() {
2091+
@Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { }
2092+
@Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { }
2093+
@Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
2094+
}
2095+
}, null);
2096+
//@formatter:on
2097+
return sslSocketFactory_ = ctx.getSocketFactory();
2098+
} catch (Exception e) {
2099+
throw e instanceof IOException ? (IOException) e : new IOException(e);
2100+
}
2101+
}
2102+
try (FileInputStream trustFile = new FileInputStream(truststoreFile)) {
2103+
KeyStore myTrustStore = KeyStore.getInstance("JKS");
2104+
myTrustStore.load(trustFile, truststorePass.toCharArray());
2105+
TrustManagerFactory trustManagerFactory = TrustManagerFactory
2106+
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
2107+
trustManagerFactory.init(myTrustStore);
2108+
SSLContext ctx = SSLContext.getInstance("TLS");
2109+
ctx.init(null, trustManagerFactory.getTrustManagers(), null);
2110+
return sslSocketFactory_ = ctx.getSocketFactory();
2111+
} catch (Exception e) {
2112+
throw e instanceof IOException ? (IOException) e : new IOException(e);
2113+
}
2114+
}
2115+
2116+
//@formatter:off
2117+
@Override
2118+
public String[] getDefaultCipherSuites() {
2119+
try { return getSSLSocketFactory().getDefaultCipherSuites();} catch (Exception e) { }
2120+
return ((SSLSocketFactory) SSLSocketFactory.getDefault()).getDefaultCipherSuites();
2121+
}
2122+
2123+
@Override
2124+
public String[] getSupportedCipherSuites() {
2125+
try { return getSSLSocketFactory().getSupportedCipherSuites(); } catch (Exception e) { }
2126+
return ((SSLSocketFactory) SSLSocketFactory.getDefault()).getSupportedCipherSuites();
2127+
}
2128+
2129+
@Override
2130+
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
2131+
return getSSLSocketFactory().createSocket(s, host, port, autoClose);
2132+
}
2133+
2134+
@Override
2135+
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
2136+
return getSSLSocketFactory().createSocket(host, port);
2137+
}
2138+
2139+
@Override
2140+
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
2141+
return getSSLSocketFactory().createSocket(host, port, localHost, localPort);
2142+
}
2143+
2144+
@Override
2145+
public Socket createSocket(InetAddress host, int port) throws IOException {
2146+
return getSSLSocketFactory().createSocket(host, port);
2147+
}
2148+
2149+
@Override
2150+
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)throws IOException {
2151+
return getSSLSocketFactory().createSocket(address, port, localAddress, localPort);
2152+
}
2153+
//@formatter:on
2154+
2155+
};
2156+
}
2157+
return null;
2158+
}
2159+
20222160
/**
20232161
* Get the clear password. The caller is responsible for clearing the array
20242162
* after it is done with the password

0 commit comments

Comments
 (0)