This is not practical to do in Java. It requires modifying the JSSE implementation or plugging in an alternative.
I eventually solved this by deploying How's My SSL and using cross-domain AJAX from the client-side to check the SSL state and report it to my app server.
You need to have unproxied direct requests from a client to properly assess the state of their SSL. Do NOT put an HTTPS load balancer in front of How's My SSL. It will break it and give you incorrect results.
Here is a snippet of client-side JavaScript that should work using the public How's My SSL service (I recommend deploying your own):
$.getJson('https://www.howsmyssl.com/a/check')
.done(function (result) {
$.post('/logs', {
name: 'howsmyssl',
level: 'info',
message: result
});
})
.fail(function(err) {
$.post('/logs', {
name: 'howsmyssl',
level: 'error',
message: 'could not reach howsmyssl'
});
});
You will need to have a REST endpoint running at /logs on your app server that can receive a POST to capture this. You can change that path and the format of the message to your heart's content. This endpoint should be authenticated and should enrich the logs with the event time, the authenticated principal (user), and possibly other information like the IP address.
The contents of result look like this (pretty-printed to make it easier to read):
{
"given_cipher_suites": [
"TLS_GREASE_IS_THE_WORD_8A",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_RSA_WITH_AES_128_GCM_SHA256",
"TLS_RSA_WITH_AES_256_GCM_SHA384",
"TLS_RSA_WITH_AES_128_CBC_SHA",
"TLS_RSA_WITH_AES_256_CBC_SHA",
"TLS_RSA_WITH_3DES_EDE_CBC_SHA"
],
"ephemeral_keys_supported": true,
"session_ticket_supported": true,
"tls_compression_supported": false,
"unknown_cipher_suite_supported": false,
"beast_vuln": false,
"able_to_detect_n_minus_one_splitting": false,
"insecure_cipher_suites": {
},
"tls_version": "TLS 1.2",
"rating": "Probably Okay"
}
You can log this to a log aggregator or a database to query it later to find specific users to call or email. You could even alert users to the gaps in their browser's TLS within your app and specifically highlight the approaching TLS 1.2 deadline and steps they can take to update their browser to compensate.