TrustManagers are responsible for managing the trust material that is used when making trust decisions, and for deciding whether credentials presented by a peer should be accepted. As of 6.3.3-preview release, Microsoft JDBC Driver for SQL Server lets the users specify a custom TrustManager to perform additional trust checking, which is based upon the needs of the environment. Newly introduced connection properties:
trustManagerClass
- The fully qualified class name of a custom javax.net.ssl.TrustManager
.
trustManagerConstructorArg
- An optional argument to pass to the constructor of the trustManagerClass
.
If trustManagerClass
is specified and an encrypted connection is requested, the custom TrustManager will be used rather than the default system JVM KeyStore based TrustManager.
Below is an example of a TrustManager that takes a single certificate as an argument and validates against it. Note that the remote certificate does not have to byte-for-byte match the constructor argument. The chain is what is being validated so you can specify a parent certificate as the constructor argument and all child certificates signed by that parent will be trusted as well.
public class SingleCertTrustManager implements X509TrustManager {
X509Certificate cert;
X509TrustManager trustManager;
public SingleCertTrustManager(String certToTrust) throws IOException, GeneralSecurityException {
InputStream in = new ByteArrayInputStream(certToTrust.getBytes());
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
try {
// Note: KeyStore requires it be loaded even if you don't load anything into it:
ks.load(null);
} catch (Exception e) {
}
CertificateFactory cf = CertificateFactory.getInstance("X509");
cert = (X509Certificate) cf.generateCertificate(in);
ks.setCertificateEntry(UUID.randomUUID().toString(), cert);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
for (TrustManager tm : tmf.getTrustManagers()) {
if (tm instanceof X509TrustManager) {
trustManager = (X509TrustManager) tm;
break;
}
}
if (trustManager == null) {
throw new GeneralSecurityException("No X509TrustManager found");
}
}
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
trustManager.checkServerTrusted(chain, authType);
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[] { cert };
}
}
You can specify the custom TrustManager using connection URL.
String url = connectionString + ";trustManagerClass=" + SingleCertTrustManager.class.getName()
+ ";trustManagerConstructorArg=cert;" + ";encrypt=true;";
Another way is to use a SQLServerDataSource object.
SQLServerDataSource ds = new SQLServerDataSource();
ds.setTrustManagerClass(SingleCertTrustManager.class.getName());
ds.setTrustManagerConstructorArg("cert");
ds.setEncrypt(true);