Mutual SSL handshake failing after Client CertificateVerify step - java

While calling an external Api secured using Mutual SSL, getting the javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
Went through the ssl debug logs and seems like client and server are able to exchange and validate the certificate and communication is failing after that step.
Putting relevant SSL debug logs :
^^^ClientHello, TLSv1.2
^^^List of CipherSuites
^^^ServerHello, TLSv1.2
^^^Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA256
** Certificate chain
..............................
................................
^^^CertificateRequest
............
^^^ServerHelloDone
^^^Certificate chain
..................
....................
no IV derived for this protocol
CertificateVerify
Signature Algorithm SHA256withRSA
main, WRITE: TLSv1.2 Handshake, length = 264
main, WRITE: TLSv1.2 Change Cipher Spec, length = 1
*** Finished
verify_data: { 46, 243, 175, 158, 127, 112, 161, 153, 5, 195, 3, 35 }
main, WRITE: TLSv1.2 Handshake, length = 80
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
Communication is failing after certificateverify step, not sure if it is due to "no IV derived for this protocol". Can someone throw some light on this, what could be possible reason for failure after client certificateverify step. Also for the client I am using Java 8 with Java Cryptography Extension (JCE) Unlimited Strength

Related

fatal, handshake_failure javax.net.ssl.SSLHandshakeException

I am trying to connect to WebService client using HttpApiClient. I am specifying
truststore = <path to Java cacerts>
truststore password = <default pass>
keystore = <custom JKS properties with all certs>
keystore password = <default pass>
When I debug the SSL using Java, I dont even see the "Server Hello message" directly the fatal, handshake error like below:
http-bio-8080-exec-9, WRITE: TLSv1 Handshake, length = 122
http-bio-8080-exec-9, READ: TLSv1 Alert, length = 2
http-bio-8080-exec-9
, RECV TLSv1 ALERT:
fatal,
handshake_failure
http-bio-8080-exec-9, called closeSocket()
http-bio-8080-exec-9, handling exception: javax.net.ssl.SSLHandshakeException:
Received fatal alert: handshake_failure
http-bio-8080-exec-9, called close()
http-bio-8080-exec-9, called closeInternal(true)
I cant debug further because there are no clues as to what is wrong. Error message does not describe anything. I have double checked all the certs are present. Any ideas on how can I debug this / what is missing ?

Trying to connect to EJBCA Web Service and getting bad_certificate at ServerHelloDone

I apologize for the really newbie quality of this question.
I have a EJBCA server set up and two CA's on it. One is the default one I created the server instance with.
I took the wsdl from EJBCA and generated Java code with it.
Using the generated java client code, I'm trying to open a connection to the EJBCA server.
According to EJBCA here: http://ejbca.sourceforge.net/ws/org/ejbca/core/protocol/ws/client/gen/package-summary.html
This the way to initialize a connection to the server.
I took the truststore.jks file from the EJBCA server as well as the superadmin.jks file from the server and put it on my local machine and made it available for my app as a resource.
val truststore = this.getClass.getClassLoader.getResource("pathto/wsTrustStore")
System.setProperty("javax.net.ssl.trustStore", truststore.getFile)
System.setProperty("javax.net.ssl.trustStorePassword","wsTrustStorePassword")
val keystore = this.getClass.getClassLoader.getResource("pathto/superadminKeyStore")
System.setProperty("javax.net.ssl.keyStore", keystore.getFile)
System.setProperty("javax.net.ssl.keyStorePassword", "superadminKeyStorePassword")
val qname = new QName(componentConfig.getString("http://ws.protocol.components.ejbca.org/"), "EjbcaWSService")
val service = new EjbcaWSService(new URL("https://myejbcaserver.com:8443/ejbca/ejbcaws/ejbcaws?wsdl"), qname)
service.getEjbcaWSPort
this is the java ssl debug logs
* CertificateRequest
Cert Types: RSA, DSS, ECDSA
Cert Authorities:
ServerHelloDone
** Certificate chain
* ClientKeyExchange, RSA PreMasterSecret, TLSv1
New I/O worker #2, WRITE: TLSv1 Handshake, length = 141
...
New I/O worker #2, WRITE: TLSv1 Change Cipher Spec, length = 1
* Finished
verify_data: { 95, 232, 182, 57, 141, 10, 130, 36, 152, 210, 86, 173 }
New I/O worker #2, WRITE: TLSv1 Handshake, length = 48
New I/O worker #2, waiting for close_notify or alert: state 1
New I/O worker #2, READ: TLSv1 Alert, length = 2
New I/O worker #2, RECV TLSv1 ALERT: fatal, bad_certificate
%% Invalidated: [Session-1, TLS_RSA_WITH_AES_128_CBC_SHA]
New I/O worker #2, called closeSocket()
New I/O worker #2, Exception while waiting for close javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
New I/O worker #2, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
Is there anyone who has experience with this that can help me out?

ssl with client authentication between cxf and IIS resulting in SocketException and SocketTimeoutException

So, I've been wrestling with a two way ssl setup between Tomcat6/Camel/Cxf to IIS6 the last few days.
A quick overview: I have a cxf consumer running in Camel in Tomcat, which calls a webservice hosted with a third party on IIS. The third party is using a 'valid' certificate, whereas we are using a self-signed certificate. IIS is configured to require client authentication.
I've gotten to the point where cxf is configured correctly, and mutual authentication is being performed.
Some gotcha's I needed to fix to get there:
allowUnsafeRenegotiation=true
https.protocols=TLSv1 (else java would send a SSLv2 client hello in the middle of the handshake)
remove the default ciphersuite filter that I copied from most CXF examples, it was too strict
All certificates, firewall settings etc. are correct, as I'm able to do a call to the third party using curl and I get a valid SOAP response back.
The problem: I get a timeout exception when sending a SOAP POST message from my application.
Looking into the ssl debug log there are some strange errors (I tried to remove all unnecessary stuff):
trigger seeding of SecureRandom
done seeding SecureRandom
Allow unsafe renegotiation: true
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
http-9203-1, setSoTimeout(120000) called
%% No cached client session
*** ClientHello, TLSv1
http-9203-1, WRITE: TLSv1 Handshake, length = 111
http-9203-1, READ: TLSv1 Handshake, length = 2454
*** ServerHello, TLSv1
RandomCookie: GMT: 1354816328 bytes = { 63, 194, 181, 182, 56, 251, 234, 198, 234, 92, 162, 175, 243, 127, 133, 182, 0, 237, 102, 9, 37, 133, 141, 3, 175, 120, 34, 92 }
Session ID: {36, 10, 0, 0, 166, 131, 36, 81, 251, 181, 83, 154, 76, 240, 235, 82, 39, 135, 239, 235, 231, 195, 17, 225, 220, 59, 105, 207, 116, 185, 114, 172}
Cipher Suite: SSL_RSA_WITH_RC4_128_MD5
Compression Method: 0
***
Warning: No renegotiation indication extension in ServerHello
%% Created: [Session-1, SSL_RSA_WITH_RC4_128_MD5]
** SSL_RSA_WITH_RC4_128_MD5
*** Certificate chain
***
Found trusted certificate:
*** ServerHelloDone
*** ClientKeyExchange, RSA PreMasterSecret, TLSv1
http-9203-1, WRITE: TLSv1 Handshake, length = 262
http-9203-1, WRITE: TLSv1 Change Cipher Spec, length = 1
*** Finished
verify_data: { 124, 172, 175, 239, 103, 187, 134, 164, 206, 241, 145, 41 }
***
http-9203-1, WRITE: TLSv1 Handshake, length = 32
http-9203-1, READ: TLSv1 Change Cipher Spec, length = 1
http-9203-1, READ: TLSv1 Handshake, length = 32
*** Finished
verify_data: { 84, 207, 104, 255, 19, 151, 27, 11, 159, 84, 124, 216 }
***
%% Cached client session: [Session-1, SSL_RSA_WITH_RC4_128_MD5]
[read] MD5 and SHA1 hashes: len = 16
0000: 14 00 00 0C 54 CF 68 FF 13 97 1B 0B 9F 54 7C D8 ....T.h......T..
Padded plaintext before ENCRYPTION: len = 365
0000: 50 4F 53 54 20 2F 69 73 61 2E 64 6C 6C 2F 41 43 POST /isa.dll/AC
http-9203-1, WRITE: TLSv1 Application Data, length = 365
Padded plaintext before ENCRYPTION: len = 1200
0000: 3C 73 6F 61 70 3A 45 6E 76 65 6C 6F 70 65 20 78 <soap:Envelope x
http-9203-1, WRITE: TLSv1 Application Data, length = 1200
default-workqueue-1, READ: TLSv1 Handshake, length = 20
This is the first handshake without client authentication (as IIS is using re-negotiation to get the client certificate). Note that a first attempt to post the SOAP message is already been made (is that normal?).
Allow unsafe renegotiation: true
Allow legacy hello messages: true
Is initial handshake: false
Is secure renegotiation: false
*** HelloRequest (empty)
Warning: continue with insecure renegotiation
%% Client cached [Session-1, SSL_RSA_WITH_RC4_128_MD5]
%% Try resuming [Session-1, SSL_RSA_WITH_RC4_128_MD5] from port 58460
*** ClientHello, TLSv1
default-workqueue-1, WRITE: TLSv1 Handshake, length = 159
default-workqueue-1, READ: TLSv1 Handshake, length = 5416
*** ServerHello, TLSv1
%% Created: [Session-2, SSL_RSA_WITH_RC4_128_MD5]
** SSL_RSA_WITH_RC4_128_MD5
*** Certificate chain
***
Found trusted certificate:
*** CertificateRequest
*** ServerHelloDone
matching alias: servercert
*** Certificate chain
*** ClientKeyExchange, RSA PreMasterSecret, TLSv1
default-workqueue-1, WRITE: TLSv1 Handshake, length = 909
*** CertificateVerify
default-workqueue-1, WRITE: TLSv1 Handshake, length = 150
[Raw write]: length = 155
default-workqueue-1, WRITE: TLSv1 Change Cipher Spec, length = 17
*** Finished
verify_data: { 242, 160, 100, 95, 172, 14, 166, 71, 158, 148, 220, 42 }
***
default-workqueue-1, WRITE: TLSv1 Handshake, length = 32
default-workqueue-1, READ: TLSv1 Change Cipher Spec, length = 17
default-workqueue-1, READ: TLSv1 Handshake, length = 32
*** Finished
verify_data: { 115, 32, 183, 236, 113, 63, 144, 117, 126, 132, 150, 67 }
***
%% Cached client session: [Session-2, SSL_RSA_WITH_RC4_128_MD5]
default-workqueue-1, handling exception: java.net.SocketException: Connection reset
%% Invalidated: [Session-2, SSL_RSA_WITH_RC4_128_MD5]
default-workqueue-1, SEND TLSv1 ALERT: fatal, description = unexpected_message
default-workqueue-1, WRITE: TLSv1 Alert, length = 18
default-workqueue-1, Exception sending alert: java.net.SocketException: Broken pipe
default-workqueue-1, called closeSocket()
default-workqueue-1, called close()
default-workqueue-1, called closeInternal(true)
The second handshake sends the client certificate to the server, I removed the detailed logging but the certificate was found and ok-ed. As you can see this handshake already ends with an error (without any delay in time).
Allow unsafe renegotiation: true
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
default-workqueue-1, setSoTimeout(120000) called
%% No cached client session
*** ClientHello, TLSv1
default-workqueue-1, WRITE: TLSv1 Handshake, length = 111
default-workqueue-1, READ: TLSv1 Handshake, length = 2454
*** ServerHello, TLSv1
Warning: No renegotiation indication extension in ServerHello
%% Created: [Session-3, SSL_RSA_WITH_RC4_128_MD5]
** SSL_RSA_WITH_RC4_128_MD5
***
Found trusted certificate:
*** ServerHelloDone
*** ClientKeyExchange, RSA PreMasterSecret, TLSv1
default-workqueue-1, WRITE: TLSv1 Handshake, length = 262
... no IV used for this cipher
default-workqueue-1, WRITE: TLSv1 Change Cipher Spec, length = 1
*** Finished
verify_data: { 130, 65, 225, 31, 41, 14, 21, 42, 102, 176, 151, 245 }
***
default-workqueue-1, WRITE: TLSv1 Handshake, length = 32
default-workqueue-1, READ: TLSv1 Change Cipher Spec, length = 1
default-workqueue-1, READ: TLSv1 Handshake, length = 32
*** Finished
verify_data: { 125, 78, 165, 103, 115, 60, 111, 169, 180, 174, 0, 169 }
***
%% Cached client session: [Session-3, SSL_RSA_WITH_RC4_128_MD5]
default-workqueue-1, WRITE: TLSv1 Application Data, length = 365
default-workqueue-1, handling exception: java.net.SocketTimeoutException: Read timed out
default-workqueue-1, called close()
default-workqueue-1, called closeInternal(true)
default-workqueue-1, SEND TLSv1 ALERT: warning, description = close_notify
default-workqueue-1, WRITE: TLSv1 Alert, length = 18
Then a third handshake is performed (normal?), and again a POST of the SOAP message is done (the write of the application date). After that POST the logging waits until the socket timeout expires (I've put it on 2 minutes or 10 secs, doesn't make a difference), after which I get a SocketTimeoutException. I tried switching to SSLv3 or 2, but that gives exactly the same result.
Any ideas what it causing this behaviour?
Should anyone ever encounter this same problem, this solved it eventually for me. I asked our third party to set this flag to true, since we only communicate with each other that shouldn't be a problem. Setting the flag to true disables renegotation, thus skipping the part in the ssl setup where it went wrong.

How to troubleshoot SSL "bad record MAC" exception

I am using an Apache CXF client, running in a Windows Java 1.6.0_29-b11 VM to connect to an IBM mainframe (I believe it is zSeries), and invoking a SOAP Web Service running there. The connection is done through SSL/TLS, and most of the time works fine.
However, from time to time I have SSL Exceptions with a bad record MAC message. Here is the output of the program using with the javax.net.debug property.
2011-11-16 12:32:37,731 INFO LoggingOutInterceptor: Outbound Message
---------------------------
ID: 29
Address: https://1.2.3.4/access/servlet/blabla.atk123
Encoding: UTF-8
Content-Type: text/xml
Headers: {Accept=[*/*], SOAPAction=["Blablaaction/ATK123.Execute"]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ATK123.Execute xmlns="Blabla"><Usrid>WA</Usrid><Usrpwd>54321</Usrpwd><Ultautid>9999</Ultautid></ATK123.Execute></soap:Body></soap:Envelope>
--------------------------------------
pool-1-thread-1, setSoTimeout(30000) called
pool-1-thread-1, WRITE: TLSv1 Application Data, length = 321
pool-1-thread-1, WRITE: TLSv1 Application Data, length = 262
pool-1-thread-1, READ: TLSv1 Application Data, length = 483
pool-1-thread-1, READ: TLSv1 Application Data, length = 16148
pool-1-thread-1, READ: TLSv1 Application Data, length = 282
%% Invalidated: [Session-1, SSL_RSA_WITH_RC4_128_SHA]
pool-1-thread-1, SEND TLSv1 ALERT: fatal, description = bad_record_mac
pool-1-thread-1, WRITE: TLSv1 Alert, length = 22
pool-1-thread-1, called closeSocket()
pool-1-thread-1, handling exception: javax.net.ssl.SSLException: bad record MAC
2011-11-16 12:32:38,511 WARN PhaseInterceptorChain: Interceptor for {Blabla}ATK123#{Blabla}Execute has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: bad record MAC
at org.apache.cxf.interceptor.LoggingInInterceptor.logging(LoggingInInterceptor.java:144)
at org.apache.cxf.interceptor.LoggingInInterceptor.handleMessage(LoggingInInterceptor.java:73)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:797)
.... (more stuff)
Unfortunately, I don't have possibilities to modify or debug the endpoint at the server.
What could be causing this?
How can I isolate and fix this behavior?
If you are getting a lot of bad packets due to some fault in your network it can happen that a bad packet will at random survive the 32-bit TCP checksum. About 1 in 4 billion bad packets will slip by TCP. Once this packet is delivered to SSL it will generate a bad record MAC for sure, because the SSL Mac is 96 bits in size.
If this is the cause, the only solution is improve the network.
Note that, in general, this is a very unlikely cause of a bad record MAC. Even a network with faulty hardware that generates bad packets is unlikely to generate them with correct IP and TCP metadata such that the packets are actually passed to the socket corresponding to the TLS connection.
This isn't related to Java, it is an SSL/TLS failure:
20 Bad record MAC fatal Possibly a bad SSL implementation, or payload
has been tampered with e.g. FTP firewall rule
on FTPS server.
It probably has something to do with the SSL implementation and the amount of data that is being sent being too big, I doubt it is random.

Java "no cipher suites in common" issue when trying to securely connect to server

I have an issue when a client (not mine) connects to my server securely.
It seems that the connection is being refused on the basis of mismatching ciphers, but I have verified that the server indeed shares some of the ciphers with the client.
Could it be an issue with the unknown cipher (Unknown 0x0:0x60)? If so, what must I do to fix it?
Java SSL logs are shown below:
Listener-https, setSoTimeout(30000) called
Worker-30, READ: SSLv3 Handshake, length = 63
*** ClientHello, SSLv3
RandomCookie: GMT: 1267050437 bytes = { 23, 244, 228, 68, 161, 225, 218, 222, 207, 128, 228, 138, 127, 141, 159, 63, 232, 48, 242, 240, 26, 76, 58, 158, 179, 0, 192, 140 }
Session ID: {}
Cipher Suites: [TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, SSL_RSA_WITH_IDEA_CBC_SHA, SSL_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_EXPORT1024_WITH_RC4_56_SHA, Unknown 0x0:0x60, SSL_RSA_EXPORT_WITH_RC4_40_MD5]
Compression Methods: { 0 }
***
Worker-30, SEND SSLv3 ALERT: fatal, description = handshake_failure
Worker-30, WRITE: SSLv3 Alert, length = 2
Worker-30, called closeSocket()
Worker-30, handling exception: javax.net.ssl.SSLHandshakeException: no cipher suites in common
Worker-30, called close()
Worker-30, called closeInternal(true)
Worker-30, called close()
Worker-30, called closeInternal(true)
Thanks,
-Ben
Adding to erickson's answer, if your certificate does not use a RSA key-pair, and instead turns out to use a DSA key-pair, then no amount of RSA cipher suite "stuffing" will aid in resolving this issue. You'll need to enable the DSA related cipher suites (they're usually indicated by the DSS keyword in them), and also have the client utilize the same cipher suites.
The reason this edge case might turn out to be your problem is due to the default behavior of the keytool utility when generating secret keypairs - DSA and not RSA is the default algorithm.
You say that some of the client's requested ciphers are enabled on your server. Have you successfully connected with one of them? For example, try OpenSSL's s_client utility with the -cipher option specifying only that cipher suite.
Perhaps the provider doesn't support all the ciphers you think you have enabled, or perhaps the unlimited strength jurisdiction files are not correctly installed on your server.

Categories