Debug Java TLS/SSL Provider
I've written wrappers for Java's X509TrustManager
and X509KeyManager
classes, and added a Provider so that you can get it hooked into the system automatically.
It's available at https://github.com/tersesystems/debugjsse.
This means you can say:
import com.tersesystems.debugjsse.DebugJSSEProvider;
DebugJSSEProvider debugJSSEProvider = new DebugJSSEProvider();
Security.addProvider(debugJSSEProvider);
debugJSSEProvider.setAsDefault();
and then anything you do after that point with JSSE will have entry/exit/exception on it.
For example, if you instantiate a trust manager and call getAcceptedIssuers
:
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(ks);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
X509ExtendedTrustManager trustManager = (X509ExtendedTrustManager) trustManagers[0];
X509Certificate[] acceptedIssuers = trustManager.getAcceptedIssuers();
will result in:
2018-07-27 06:30:04,545 TRACE [main] - getAcceptedIssuers: args = [] with delegate = sun.security.ssl.X509TrustManagerImpl@29444d75
2018-07-27 06:30:04,549 TRACE [main] - getAcceptedIssuers: args = [] with delegate = sun.security.ssl.X509TrustManagerImpl@29444d75, result = [Ljava.security.cert.X509Certificate;@7bfcd12c
You can also wrap your trust manager explicitly, of course:
X509ExtendedTrustManager delegate = ...
Debug debug = ...
X509ExtendedTrustManager tm = new DebugX509ExtendedTrustManager(delegate, debug);
but if you have libraries that instantiate their own trust managers, such as Kafka Client's SslFactory, then hooking in the provider is the only way to get at it.
Note that this debugging mechanism is distinct from using javax.net.debug
in a few ways. Here's what is wrong with JSSE debugging:
javax.net.debug
is hardcoded toSystem.out.println
.javax.net.debug
mixes outputs coming from different threads.javax.net.debug
does not give you timestamp information.javax.net.debug
does not give you method level granularity.javax.net.debug
settings cannot be changed at runtime.javax.net.debug
does not respect verbosity settings.
By contrast, DebugJSSE:
- Works with any logging framework.
- Has flexibility to log only by delegate or by individual method or argument.
- Lets you swap out the results of the delegate's method call.
I've been meaning to write this for a while. What really cracked it was the X509ExtendedKeyManager
abstract class adds two methods, chooseEngineClientAlias
and chooseEngineServerAlias
, but silently returns null for both of them. And then javax.net.debug
doesn't integrate with SLF4J, and an async appender and println do not get along.
It is all fixed. It is done. May you never have to go through this.
You may also like https://github.com/scholzj/AliasKeyManager which was used as inspiration, and will pick out a preferred client alias from a key manager. Also see the previous JSSE posts if you are morbidly curious.