Java not providing client certificate for mutual S

2020-07-18 02:37发布

问题:

I’m trying to connect with mutual SSL from a Java SpringBoot application to a NetScaler endpoint. I am able to connect as expected on the command line via OpenSSL with the following command:

openssl s_client -connect xxxx.xxxx.xxxx.xxx:443 -cert cert.cer -key private.key

Which gives the following output:

CONNECTED(00000003)
---
Certificate chain
0 s:/C=GB/ST=London/L=London/O=XXXX XXXXX XXX/OU=Infrastructure Services/CN=sit1.xxxxxxx.xxxxxxx.com
   i:/C=US/O=Symantec Corporation/OU=Symantec Trust Network/CN=Symantec Class 3 Secure Server CA - G4
1 s:/C=US/O=Symantec Corporation/OU=Symantec Trust Network/CN=Symantec Class 3 Secure Server CA - G4
   i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5
2 s:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5
   i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIGEDCCBPigAwIBAgIQfcfqyYG0Xonen/ZVJX6uGzANBgkqhkiG9w0BAQsFADB+
...
/mYUOtT8fbbe1v+erDvbwbXikyE=
-----END CERTIFICATE-----
subject=/C=GB/ST=London/L=London/O=XXXX XXXXX XXX/OU=Infrastructure Services/CN=sit1.xxxxxxx.xxxxxxx.com
issuer=/C=US/O=Symantec Corporation/OU=Symantec Trust Network/CN=Symantec Class 3 Secure Server CA - G4
---
Acceptable client certificate CA names
/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5
/C=US/O=Symantec Corporation/OU=Symantec Trust Network/CN=Symantec Class 3 Secure Server CA - G4
Client Certificate Types: RSA sign, DSA sign
Requested Signature Algorithms: RSA+MD5:RSA+SHA1:RSA+SHA256:DSA+SHA1
Shared Requested Signature Algorithms: RSA+SHA1:RSA+SHA256:DSA+SHA1
---
SSL handshake has read 4672 bytes and written 2489 bytes
---
New, TLSv1/SSLv3, Cipher is AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : AES256-SHA
    Session-ID: BFXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX0D
    Session-ID-ctx: 
    Master-Key: F7FXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX65
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1467272199
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)

In order connect from the Java application I’ve combined the key and the certificate in cert.cer and private.key files with the following command:

openssl pkcs12 -export -in cert.cer -inkey private.key -out keystore.p12

I start the Spring application with the following parameters:

-Djavax.net.debug=ssl
-Djavax.net.ssl.keyStore=C:/opt/wtr-certs/keystore.p12
-Djavax.net.ssl.keyStorePassword=XXXXXXXXX

I can clearly see my keystore getting loaded as the Java application tries to connect but it seems to fail when trying to present the client certificate to the server.

Loading the keystore:

trigger seeding of SecureRandom
done seeding SecureRandom
keyStore is : C:/opt/wtr-certs/keystore.p12
keyStore type is : jks
keyStore provider is : 
init keystore
init keymanager of type SunX509
***
found key for : xxxx.xxxx.xxx.xxxxxxxx.xxx
chain [0] = [
[
  Version: V3
  Subject: CN=xxxx.xxxx.xxx.xxxxxxxx.xxx, OU=Infrastructure Services, O=XXXX XXXX XXX, L=London, ST=London, C=GB
  Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11

  Key:  Sun RSA public key, 2048 bits
  modulus: 
...

I believe the Java application isn't presenting the certificate correctly as shown by this section of the logs:

*** CertificateRequest
Cert Types: RSA, DSS
Supported Signature Algorithms: MD5withRSA, SHA1withRSA, SHA256withRSA, SHA1withDSA
Cert Authorities:
<CN=VeriSign Class 3 Public Primary Certification Authority - G5, OU="(c) 2006 VeriSign, Inc. - For authorized use only", OU=VeriSign Trust Network, O="VeriSign, Inc.", C=US>
<CN=Symantec Class 3 Secure Server CA - G4, OU=Symantec Trust Network, O=Symantec Corporation, C=US>
*** ServerHelloDone
Warning: no suitable certificate found - continuing without client authentication
*** Certificate chain
<Empty>
***

There appears to be a similar, older, question here: Java not sending client certificate but it has no answers. How can I persuade Java to find a send the correct certificate? I can provide additional logging if required.