I'm troubleshooting some SSL/TLS problems, with -Djavax.net.debug
on the command line and it would help immensely to have some logging where the server certificate is logged in a format which can be parsed and read.
I tried following debug settings:
-Djavax.net.debug=ssl:record:plaintext
-Djavax.net.debug=ssl:handshake:verbose:keymanager:trustmanager
-Djavax.net.debug=ssl:handshake:verbose
The closed I came was with the last statement which logs the following:
10/11/2021 10:27:36 "version" : "v3",
10/11/2021 10:27:36 "serial number" : "I8 00 00 00 00 D2 91 BH 88 A4 10 58 00 00 02 00 04 9E 4B",
10/11/2021 10:27:36 "signature algorithm": "SHA256withRSA",
10/11/2021 10:27:36 "issuer" : "CN=test, DC=test, DC=test, DC=com",
10/11/2021 10:27:36 "not before" : "2021-07-23 17:38:30.000 UTC",
10/11/2021 10:27:36 "not after" : "2026-07-22 17:38:30.000 UTC",
10/11/2021 10:27:36 "subject" : "CN=CNTest, OU=TIS, O="ACME Inc", L=France, ST=Paris, C=EU",
10/11/2021 10:27:36 "subject public key" : "RSA",
10/11/2021 10:27:36 "extensions" : [
...
]
Which is already useful but it would help immensely to have the server certificate in a readable format to further troubleshoot the problem. It would help to compare the certificate we received with the actual that is on the server.
I already tried to use the openssl
tooling to print the certificates. But the Java application is also using queues which seems to use different certificates than I was supplied and isn't easy to extract the queue certificates with the openssl
tooling.
sources:
- https://colinpaice.blog/2020/04/05/using-java-djavax-net-debug-to-examine-data-flows-including-tls/
- https://access.redhat.com/solutions/973783
- Using openssl to get the certificate from a server
- https://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/ReadDebug.html
CodePudding user response:
It is not possible to get the server certificate as pem with javax.net.debug
You can try the following snippet which I also use for my own project:
Map<String, List<String>> certificates = CertificateUtils.getCertificateAsPem(
"https://github.com/",
"https://stackoverflow.com/");
It will extract all the certificates for the given urls in pem format. It is available within my own library which is publicly available here: GitHub - SSLContext Kickstart
Or you can also do the same with a CLI, see here: GitHub - Certificate Ripper Below is an example of the snippet above:
crip print -u=https://github.com -u=https://stackoverflow.com -f=pem
Please let me know if this is something which will do the trick for you
CodePudding user response:
For the old stack (below 8u261 or 11) in all cases, and the new stack when the protocol used (negotiated) is TLS1.2 or below, javax.net.debug=ssl:handshake:packet
will show you a 'raw write' for each outgoing record with (all) the data in hex and ASCII, and at least two 'raw read' for each incoming record (one for the header of 5 bytes, and one or more for the data) ditto. The fields going into an outgoing record are shown before the record, while the fields decoded from an incoming record are shown after it. For example on a connection to https://example.com
after (build and) write the ClientHello and read (and decode) the ServerHello, I get for the Certificate message/record this pastebin (otherwise exceeds Stack size limit).
Take the body data (only) and on Unix, or WSL, run it through cut -c9-58 <hex | xxd -r -p >bin
(for old stack -c7-56
). The file bin
now contains the Certificate message exactly as received: the first byte is 0B, the next three bytes are the (bigendian) length of the body of the message, the next three bytes are the length of the certificate list, and the next three are the length of the first certificate. To separate out that first certificate, do tail -c 11 bin | head -c$((0x$(xxd -p -s7 -l3 bin))) >cert1
. You can now convert the cert to PEM with openssl x509 -inform d <cert1
or examine it with any other x509
options, or examine it with keytool -printcert -file cert1
, or any other suitable tool. If you want (all or some of) the other cert(s) in the chain, it's a little more complicated.
TLS1.3, in new stack only, is slightly different. It encrypts the Certificate message and may have a hello-retry cycle, may have an early CCS, and will have an EncryptedExtensions message before the Certificate. Add :plaintext
to the sysprop and for each incoming record you get a raw read of the header (5 bytes) in clear, a raw read of the body in cipher, and a decryption of the body, like this for the Certificate message/record.
This message differs slightly from the previous protocol version by having one byte of 00 between the message length and the certificate-list length, so change to: tail -c 12 bin | head -c$((0x$(xxd -p -s8 -l3 bin)))
.
Note some servers may combine messages in one handshake record (or encrypted handshake record), rather than using a separate record for each as example.com did, which will require a slight variation. If you have an example (accessible) of such, I will adjust.
However, I have no idea what you mean by 'queues' in an SSL/TLS connection, and why the much easier openssl s_client
isn't usable. If you mean virtual hosting with the server choosing among multiple certificates using SNI, see the man page description of the -servername x
option.