SSLHandshakeException when connection to WebSphere MQ via JMS/JNDI - java

I am in the process of configuring WebSphere MQ and SSL and then connect to it using Java and JMS/JNDI. The version I use is 6.0.1.1. Here are the steps I followed but I can't make it run because I get an SSL exception.
Step 1: Configure SSL for MQ Series
export JAVA_HOME=/opt/mqm/ssl
cd /var/mqm/qmgrs/MYQMGR/ssl
# Set up the key repository
gsk7cmd -keydb -create -db keydb.kdb -pw password -type cms -expire 1500 -stash
# Create a self-signed personal certificate
gsk7cmd -cert -create -db keydb.kdb -pw password -label ibmwebspheremqmyqmgr -dn "CN=My Queue Manager,O=My Company,C=UK" -size 1024 -x509version 3 -expire 365
# Export your personal certificate
gsk7cmd -cert -extract -db filename -pw password -label ibmwebspheremqmyqmgr -target myqmgr.cert.arm -format ascii
Step 2: Configure SSL for Java
# Generate the private/public key pair
# keypass option is the password to protect the private key
# storepass option is the password to protect the keystore
keytool -genkey -keystore keystore -storepass storepass -keypass keypass -dname "cn=My Java Client,O=My Company,C=UK" -alias ClientMQ -keyalg RSA -keysize 2048
# Export the public key if you need 2-way authentification
keytool -export -keystore keystore -storepass storepass -alias ClientMQ -file client.cer
# Import MQ public certificate into the truststore
# storepass option is the password to protect the keystore
keytool -import -keystore truststore -storepass trustpass -keypass keypass -alias ibmwebspheremqmyqmgr -file myqmgr.cert.arm
Step 3: Configure MQ Bindings
The SSL.CHANNEL has been create with the command: DEFINE CHANNEL(SSL.CHANNEL) CHLTYPE(SVRCONN) TRPTYPE(TCP) SSLCIPH(RC4_SHA_US) SSLCAUTH(OPTIONAL) DESCR('Channel using SSL')
JMSAdmin.config
INITIAL_CONTEXT_FACTORY=com.sun.jndi.fscontext.RefFSContextFactory
PROVIDER_URL=file:///opt/mqm/java/bin/JNDI
SECURITY_AUTHENTICATION=none
cd /opt/mqm/java/bin
. setjmsenv
./JMSAdmin -v -cfg JMSAdmin.config
DEFINE QCF(QCF_NAME) SYNCPOINTALLGETS(YES) HOSTNAME(HOST) PORT(1414) TRANSPORT(client) QMANAGER(MYQMGR) CHANNEL(SSL.CHANNEL) SSLCIPHERSUITE(SSL_RSA_WITH_RC4_128_SHA)
DEFINE Q(MYQNAME) QMANAGER(MYQMGR) QUEUE(LOCALQUEUE)
Step 4: Figure out why I get the exception
When I ran my Java app I get the following exception when calling connectionFactory.createQueueConnection();:
javax.jms.JMSException: MQJMS2005: failed to create MQQueueManager for 'xxxx:xxxxx'
com.ibm.mq.MQException: MQJE001: Completion Code 2, Reason 2397
javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
Here is the SSL trace:
keyStore is :
keyStore type is : jks
keyStore provider is :
init keystore
init keymanager of type SunX509
trustStore is: c:\home\doc\jsse\truststore
trustStore type is : jks
trustStore provider is :
init truststore
adding as trusted cert:
Subject: CN=My Queue Manager,O=My Company,C=UK
Issuer: CN=My Queue Manager,O=My Company,C=UK
Algorithm: RSA; Serial number: 0x5072a61a
Valid from Sun Oct 07 12:08:26 CEST 2012 until Tue Oct 08 12:08:26 CEST 2013
trigger seeding of SecureRandom
done seeding SecureRandom
%% No cached client session
*** ClientHello, TLSv1
RandomCookie: GMT: 1349707178 bytes = { 204, 18, 167, 43, 13, 107, 252, 221, 191, 41, 25, 59, 207, 92, 67, 219, 251, 104, 195, 209, 7, 129, 104, 171, 139, 47, 163, 71 }
Session ID: {}
Cipher Suites: [SSL_RSA_WITH_RC4_128_SHA]
Compression Methods: { 0 }
***
[write] MD5 and SHA1 hashes: len = 45
0000: 01 00 00 29 03 01 50 73 E6 AA CC 12 A7 2B 0D 6B ...)..Ps.....+.k
0010: FC DD BF 29 19 3B CF 5C 43 DB FB 68 C3 D1 07 81 ...).;.\C..h....
0020: 68 AB 8B 2F A3 47 00 00 02 00 05 01 00 h../.G.......
Thread pool thread #0, WRITE: TLSv1 Handshake, length = 45
[write] MD5 and SHA1 hashes: len = 44
0000: 01 03 01 00 03 00 00 00 20 00 00 05 50 73 E6 AA ........ ...Ps..
0010: CC 12 A7 2B 0D 6B FC DD BF 29 19 3B CF 5C 43 DB ...+.k...).;.\C.
0020: FB 68 C3 D1 07 81 68 AB 8B 2F A3 47 .h....h../.G
Thread pool thread #0, WRITE: SSLv2 client hello message, length = 44
[Raw write]: length = 46
0000: 80 2C 01 03 01 00 03 00 00 00 20 00 00 05 50 73 .,........ ...Ps
0010: E6 AA CC 12 A7 2B 0D 6B FC DD BF 29 19 3B CF 5C .....+.k...).;.\
0020: 43 DB FB 68 C3 D1 07 81 68 AB 8B 2F A3 47 C..h....h../.G
Thread pool thread #0, received EOFException: error
Thread pool thread #0, handling exception: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
Thread pool thread #0, SEND TLSv1 ALERT: fatal, description = handshake_failure
Thread pool thread #0, WRITE: TLSv1 Alert, length = 2
[Raw write]: length = 7
0000: 15 03 01 00 02 02 28 ......(
Thread pool thread #0, called closeSocket()
Finalizer, called close()
Finalizer, called closeInternal(true)
On MQ side:
AMQ9660: SSL key repository: password stash file absent or unusable.
EXPLANATION:
The SSL key repository cannot be used because MQ cannot obtain a password to
access it. Reasons giving rise to this error include:
(a) the key database file and password stash file are not present in the
location configured for the key repository,
(b) the key database file exists in the correct place but that no password
stash file has been created for it,
(c) the files are present in the correct place but the userid under which MQ is
running does not have permission to read them,
(d) one or both of the files are corrupt.
But none of them applies to me.
ls -ltr /var/mqm/qmgrs/MYQMGR/ssl/
total 235
-rw-r--r-- 1 mqm mqm 129 Oct 8 12:00 keydb.sth
-rw-r--r-- 1 mqm mqm 115080 Oct 8 12:08 keydb.kdb
-rw-r--r-- 1 mqm mqm 80 Oct 8 12:08 keydb.rdb
-rw-r--r-- 1 mqm mqm 80 Oct 8 12:08 keydb.crl

Stupid mistake: alter qmgr SSLKEYR('/var/mqm/qmgrs/MYQMGR/ssl/keydb') fixes the issue.

Related

How do I get OpenJDK 16 to talk with an SSL enabled nginx server?

I'm running a spring boot application that needs to make an https call to an nginx server. The application is running on CentOS 7 with OpenJDK 16.
Following this more or less, I gathered a list of all the ciphers available to the JVM:
TLS_AES_256_GCM_SHA384
TLS_AES_128_GCM_SHA256
TLS_CHACHA20_POLY1305_SHA256
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
TLS_DHE_DSS_WITH_AES_256_GCM_SHA384
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
TLS_DHE_DSS_WITH_AES_128_GCM_SHA256
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_DSS_WITH_AES_256_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_RSA_WITH_AES_128_GCM_SHA256
TLS_RSA_WITH_AES_256_CBC_SHA256
TLS_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_EMPTY_RENEGOTIATION_INFO_SCSV
In nginx, I have the following:
ssl_certificate /etc/ssl/cert;
ssl_certificate_key /etc/ssl/key;
ssl_protocols TLSv1.2 TLSv1.3;
resolver 169.254.169.253;
ssl_prefer_server_ciphers off;
ssl_ciphers ...keys here...;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
ssl_dhparam /etc/ssl/dhparam;
I've tried every one of the ciphers available to my JVM in place of ...keys here... and they all result in nginx failing to start with:
nginx: [emerg] SSL_CTX_set_cipher_list("...") failed (SSL: error:1410D0B9:SSL routines:SSL_CTX_set_cipher_list:no cipher match)
I can add a list more like I would expect, such as:
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
nginx starts at this point - and most applications like Chrome, wget, etc are fine with it. Oracle's JDK 11 on my laptop also connects to it without issue. However the OpenJDK based application refuses to connect:
"ClientHello": {
"client version" : "TLSv1.2",
"random" : "1F F7 66 B2 EB 52 F0 3A 99 E6 9B A7 10 1A 85 E1 0C FF DC 36 06 C7 52 38 0C 8A 27 9F 21 AA 0E 7D",
"session id" : "70 E0 79 AB 78 7B 48 22 41 22 1E 38 64 01 BF E8 7D E0 2C DD BA 08 09 00 20 B2 39 8D 53 B4 65 A2",
"cipher suites" : "[TLS_AES_256_GCM_SHA384(0x1302), TLS_AES_128_GCM_SHA256(0x1301), TLS_CHACHA20_POLY1305_SHA256(0x1303), TLS_DHE_RSA_WITH_AES_256_GCM_SHA384(0x009F), TLS_DHE_DSS_WITH_AES_256_GCM_SHA384(0x00A3), TLS_DHE_RSA_
WITH_AES_128_GCM_SHA256(0x009E), TLS_DHE_DSS_WITH_AES_128_GCM_SHA256(0x00A2), TLS_DHE_RSA_WITH_AES_256_CBC_SHA256(0x006B), TLS_DHE_DSS_WITH_AES_256_CBC_SHA256(0x006A), TLS_DHE_RSA_WITH_AES_128_CBC_SHA256(0x0067), TLS_DHE_DSS_WITH_AE
S_128_CBC_SHA256(0x0040), TLS_DHE_RSA_WITH_AES_256_CBC_SHA(0x0039), TLS_DHE_DSS_WITH_AES_256_CBC_SHA(0x0038), TLS_DHE_RSA_WITH_AES_128_CBC_SHA(0x0033), TLS_DHE_DSS_WITH_AES_128_CBC_SHA(0x0032), TLS_RSA_WITH_AES_256_GCM_SHA384(0x009D
), TLS_RSA_WITH_AES_128_GCM_SHA256(0x009C), TLS_RSA_WITH_AES_256_CBC_SHA256(0x003D), TLS_RSA_WITH_AES_128_CBC_SHA256(0x003C), TLS_RSA_WITH_AES_256_CBC_SHA(0x0035), TLS_RSA_WITH_AES_128_CBC_SHA(0x002F)]",
...
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.252 UTC|Alert.java:238|Received alert message (
"Alert": {
"level" : "fatal",
"description": "handshake_failure"
}
)
I also ran across this - I'm assuming this means that the JDK cipher named TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 for instance should be DHE-RSA-AES256-GCM-SHA384 in nginx/OpenSSL. So I tried a modified cipher list in nginx of:
ssl_ciphers DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA;
but still the same result. In the nginx logs:
2022/03/22 06:05:55 [info] 74#74: *22 SSL_do_handshake() failed (SSL: error:141F7065:SSL routines:final_key_share:no suitable key share) while SSL handshaking, client: #.#.#.#, server: 0.0.0.0:443
and in the Java service logs:
javax.net.ssl|DEBUG|18|http-nio-8080-exec-3|2022-03-22 06:05:56.332 UTC|ClientHello.java:652|Produced ClientHello handshake message (
"ClientHello": {
"client version" : "TLSv1.2",
"random" : "A9 28 13 AB 6F 82 B6 F1 88 E9 2C C9 CE 84 55 15 84 9E 25 E9 57 72 C3 BA CF 1C 9B 45 3D 13 28 7F",
"session id" : "5E F8 0E 52 83 A9 C2 AF DE 6C BD E4 D7 3C A5 FD D9 00 6F 1C D7 CA 07 E0 63 EF C4 24 CF 57 9F A1",
"cipher suites" : "[TLS_AES_256_GCM_SHA384(0x1302), TLS_AES_128_GCM_SHA256(0x1301), TLS_CHACHA20_POLY1305_SHA256(0x1303), TLS_DHE_RSA_WITH_AES_256_GCM_SHA384(0x009F), TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256(0xCCAA), TLS_DH
...
)
javax.net.ssl|DEBUG|18|http-nio-8080-exec-3|2022-03-22 06:05:56.334 UTC|Alert.java:238|Received alert message (
"Alert": {
"level" : "fatal",
"description": "handshake_failure"
}
)
javax.net.ssl|ERROR|18|http-nio-8080-exec-3|2022-03-22 06:05:56.335 UTC|TransportContext.java:361|Fatal (HANDSHAKE_FAILURE): Received fatal alert: handshake_failure (
"throwable" : {
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
...
I can't seem to find any good documentation on adding additional ciphers to the JVM, only enabling ones that are present but not enabled for some reason. I've seen some vague references to BouncyCastle, but unclear how to properly use that for this purpose, especially since I won't be creating the sockets myself (using a library that needs to make the call).
I also can't seem to figure out how to configure nginx/OpenSSL to enable additional ciphers to support what the Java application is expecting. I'm using nginx 1.21.6 and OpenSSL 1.1.1k.
So... How do I add/configure ciphers to make the two play well together?
For me, the issue came down to an outdated installation of OpenSSL.
I mistakenly read the OpenSSL version from the docker host (1.1.1x) instead of from the container (don't remember the version, but was from 2017). Unfortunately, this can't easily be updated in CentOS 7 - nothing from the package manager, and compiling from source runs into all sorts of issues. But once past those issues, the list of ciphers was about 5x as long and the connection worked fine.
I then switched to Ubuntu 20.04, which made the installation of OpenSSL much easier (1.1.1f comes standard from the package manager). SSL handshake went through as expected.
On to the next problem - even with a successful SSL negotiation, for some reason all SSL connections are timing out after 25ms... but that'll be another topic (here for anyone going down the same rathole as I am).

JDK 11 PreMaster Secret debugging

Using this simple https server slightly modified to replace var with Java 8 compatible types, I can run it as such:
$ java8 -cp . -Djavax.net.debug=ssl,keygen javatester.SimpleHTTPSServer | grep Nonce -C 5
SESSION KEYGEN:
PreMaster Secret:
0000: A7 7C E0 10 EB E5 7C 16 CF 70 65 30 04 AE 5B BC .........pe0..[.
0010: 6F 61 52 6C FC 71 58 D9 F4 BD 10 70 69 10 62 2A oaRl.qX....pi.b*
CONNECTION KEYGEN:
Client Nonce:
0000: A3 E4 45 27 77 6C 0D 5E BD F1 4E 9D 1E 2E 10 02 ..E'wl.^..N.....
0010: 7F 6E A1 EC C2 BC 40 E3 1E 32 A9 B9 13 3B 6C B5 .n....#..2...;l.
Server Nonce:
0000: 5E B5 99 F9 02 EE C3 9E 84 30 01 32 B4 04 BA 38 ^........0.2...8
0010: B1 D9 B2 D9 6E 54 F4 4C BF DC 60 98 97 AD 8B B2 ....nT.L..`.....
Master Secret:
0000: D6 14 BF 8E FF 69 93 9C DB 58 35 AC 65 EF 5B A2 .....i...X5.e.[.
0010: 79 D7 3D 67 76 F7 CA 82 69 F9 30 34 9A C8 E7 EB y.=gv...i.04....
These values I can use to create a Wireshark-capable premaster secret log file to decode the connection. However, when I run this with jdk 11, I don't get any keygen output:
$ java11 -cp . -Djavax.net.debug=ssl,keygen javatester.SimpleHTTPSServer
Start single-threaded server at /0.0.0.0:8443
javax.net.ssl|DEBUG|01|main|2020-05-08 13:51:10.479 EDT|SSLCipher.java:437|jdk.tls.keyLimits: entry = AES/GCM/NoPadding KeyUpdate 2^37. AES/GCM/NOPADDING:KEYUPDATE = 137438953472
javax.net.ssl|DEBUG|01|main|2020-05-08 13:51:24.367 EDT|SSLCipher.java:1824|KeyLimit read side: algorithm = AES/GCM/NOPADDING:KEYUPDATE
countdown value = 137438953472
javax.net.ssl|DEBUG|01|main|2020-05-08 13:51:24.369 EDT|SSLCipher.java:1978|KeyLimit write side: algorithm = AES/GCM/NOPADDING:KEYUPDATE
countdown value = 137438953472
javax.net.ssl|ALL|01|main|2020-05-08 13:51:24.382 EDT|X509Authentication.java:243|No X.509 cert selected for EC
javax.net.ssl|ALL|01|main|2020-05-08 13:51:24.382 EDT|X509Authentication.java:243|No X.509 cert selected for EC
javax.net.ssl|ALL|01|main|2020-05-08 13:51:24.382 EDT|X509Authentication.java:243|No X.509 cert selected for EC
javax.net.ssl|DEBUG|01|main|2020-05-08 13:51:24.414 EDT|SSLCipher.java:1978|KeyLimit write side: algorithm = AES/GCM/NOPADDING:KEYUPDATE
countdown value = 137438953472
javax.net.ssl|DEBUG|01|main|2020-05-08 13:51:24.417 EDT|SSLCipher.java:1824|KeyLimit read side: algorithm = AES/GCM/NOPADDING:KEYUPDATE
countdown value = 137438953472
GET / HTTP/1.1
Host: localhost:8443
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Upgrade-Insecure-Requests: 1
javax.net.ssl|ALL|01|main|2020-05-08 13:51:24.423 EDT|SSLSocketImpl.java:1002|Closing output stream
javax.net.ssl|DEBUG|01|main|2020-05-08 13:51:24.423 EDT|SSLSocketImpl.java:670|close outbound of SSLSocket
javax.net.ssl|ALL|01|main|2020-05-08 13:51:24.424 EDT|SSLSocketImpl.java:877|Closing input stream
javax.net.ssl|DEBUG|01|main|2020-05-08 13:51:24.425 EDT|SSLSocketImpl.java:636|close inbound of SSLSocket
javax.net.ssl|DEBUG|01|main|2020-05-08 13:51:24.425 EDT|SSLSocketImpl.java:473|duplex close of SSLSocket
javax.net.ssl|DEBUG|01|main|2020-05-08 13:51:24.425 EDT|SSLSocketImpl.java:1381|close the SSL connection (passive)
I wondered if this was no longer supported, but the help command suggests it is:
$ java11 -cp . -Djavax.net.debug=help javatester.SimpleHTTPSServer
(...snipped)
ssl turn on ssl debugging
The following can be used with ssl:
record enable per-record tracing
handshake print each handshake message
keygen print key generation data
session print session activity
(snipped...)
How can I export the premaster secret from jdk11 connections so I can use them in Wireshark?
If the newer Java versions do no longer output the pre-master secret you can use the project extract-tls-secrets.
Decrypt HTTPS/TLS connections on-the-fly. Extract the shared secrets from secure TLS connections for use with Wireshark. Attach to a Java process on either side of the connection to start decrypting.
The code of this project can be injected at start-up into the TLS server or client using the javaagent system, or you can connect to an existing Java process (I assume via Java debugger interface).

Java SSL handshake always get "PKIX path building failed" for any domain

I get this error message when build a gradle project in idea:
> Could not resolve io.spring.gradle:dependency-management-plugin:1.0.6.RELEASE.
> Could not get resource 'https://plugins.gradle.org/m2/io/spring/gradle/dependency-management-plugin/1.0.6.RELEASE/dependency-management-plugin-1.0.6.RELEASE.pom'.
> Could not HEAD 'https://plugins.gradle.org/m2/io/spring/gradle/dependency-management-plugin/1.0.6.RELEASE/dependency-management-plugin-1.0.6.RELEASE.pom'.
> sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
I found that all ssl handshack in java get the same error.
I use SSLPoke to check some domains, such as stackoverflow.com, github.com, all of them return the same error message: "PKIX path building failed". But I can visit this sites on the browser with no error.
I try to change the jdk from jdk11 to jdk8, and try to reinstall the jdk, but also get the same result. I check the default jdk keystore by keytool -list command, and it looks like no problem.
I try to debug and found that the certificate looks weird, it only has one cert in the cert chain, and the Issuer is always CN=GlobalSign Root CA, C=EN, no matter which domain. Such as stackoverflow.com:
[
[
Version: V3
Subject: CN=*.stackexchange.com
Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11
Key: Sun RSA public key, 1024 bits
modulus: 129343236870246922217917428341848371602010941604981692235450252202393431416169367447480541321401904173442212978999107322095875009215075266308069463921433338673265672174736174633404814882397952490528363553362969976277321592285699339620492251079789709609773064124868826755702755848122392099215387700370904957487
public exponent: 65537
Validity: [From: Fri Jul 26 22:38:33 CST 2019,
To: Thu Oct 24 22:38:33 CST 2019]
Issuer: CN=GlobalSign Root CA, C=EN
SerialNumber: [ bae8be0e 04cb0e2b 0e83d26f c22ba1e7]
Certificate Extensions: 3
[1]: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:false
PathLen: undefined
]
[2]: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
serverAuth
clientAuth
]
[3]: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
DNSName: *.askubuntu.com
DNSName: *.blogoverflow.com
DNSName: *.mathoverflow.net
DNSName: *.meta.stackexchange.com
DNSName: *.meta.stackoverflow.com
DNSName: *.serverfault.com
DNSName: *.sstatic.net
DNSName: *.stackexchange.com
DNSName: *.stackoverflow.com
DNSName: *.stackoverflow.email
DNSName: *.superuser.com
DNSName: askubuntu.com
DNSName: blogoverflow.com
DNSName: mathoverflow.net
DNSName: openid.stackauth.com
DNSName: serverfault.com
DNSName: sstatic.net
DNSName: stackapps.com
DNSName: stackauth.com
DNSName: stackexchange.com
DNSName: stackoverflow.blog
DNSName: stackoverflow.com
DNSName: stackoverflow.email
DNSName: stacksnippets.net
DNSName: superuser.com
]
]
Algorithm: [SHA256withRSA]
Signature:
0000: B5 35 45 AA 8D 99 FF F1 3F 5D CA 94 6D 5F 6A 12 .5E.....?]..m_j.
0010: D2 39 0E 66 1D 11 63 80 12 0C A1 2D A7 CA A7 39 .9.f..c....-...9
0020: 36 4B A4 12 45 AD A8 4D E5 1E DD 7B AF A9 10 CD 6K..E..M........
0030: ED 5B 15 76 F2 49 41 F8 AB 82 67 5D E8 09 0A 65 .[.v.IA...g]...e
0040: 7D BC 22 C5 53 7D DD 32 15 9E 88 92 FB 35 C2 C8 ..".S..2.....5..
0050: 86 E0 53 BF 32 72 DA FA CE 27 A0 BA 78 5F DA B2 ..S.2r...'..x_..
0060: CA C3 8B 14 0B C5 EF E1 4D 96 8F BF 4A AC B0 DB ........M...J...
0070: 24 5E 20 7C 32 51 58 93 36 0B 1A 2A BB 88 A3 9B $^ .2QX.6..*....
0080: DF 6F B4 F1 25 CD B8 C6 C1 1D 19 BD A7 54 27 73 .o..%........T's
0090: 56 A8 5D 78 13 E6 86 00 59 E2 32 34 34 28 6D 4F V.]x....Y.244(mO
00A0: 30 39 F6 3A 2E 43 1F E6 7B 43 57 C2 79 E5 87 4C 09.:.C...CW.y..L
00B0: CB 9E 95 6D 99 6D 46 AD FA 7D 74 BA 12 D9 D0 8B ...m.mF...t.....
00C0: 93 B7 49 E4 61 FD 4B 73 00 FA 0E 61 9A 4E DA C1 ..I.a.Ks...a.N..
00D0: D3 B9 45 B1 79 13 BB 90 02 98 24 E7 4D 31 01 52 ..E.y.....$.M1.R
00E0: 1F 38 47 0B 4E 4C E0 91 2A 8A 05 6E 20 89 81 E3 .8G.NL..*..n ...
00F0: 3B E3 60 D5 70 DF 28 D3 58 E7 D6 FF A6 CA 1D B6 ;.`.p.(.X.......
]
Different to the normal cert:
Key length. Normal is 2048 bits, not 1024 bits.
Issuer. Normal is CN=Let's Encrypt Authority X3, O=Let's Encrypt, C=US
Certificate Extensions. Normal has 9 extensions, not 3.
modulus, SerialNumber, Signature. Their value is different to the normal.
Normal cert has a intermediate certificate in the cert chain, Issuer is CN=DST Root CA X3, O=Digital Signature Trust Co.
So, how can I find the real reason of the problem, and how to solve the problem.
Meta: not an answer yet but need space to respond to data
Aside: I assume you are in timezone +8. The PCAPs are 09-18 01:43:00-01 and 01:49:52-54 Z
while the Java-log timestamps are 09-18 09:42:59-43:01 and 09:49:51-54 CST.
First, the Java-logs. In the success log at line 3652, the ServerHello selects TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
and agrees to extensions renegotiation_info server_name ec_point_formats status_request extended_master_secret;
this is consistent with the real stackoverflow servers in my testing. In the fail log at 3651,
it selects TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 and agrees to only renegotiation_info ec_point_formats,
which is substantially different behavior. We then see the different certificates,
with success.txt getting the correct leaf cert (under Let's Encrypt) and chain cert (under DST),
and fail.txt getting the bogus cert under "CN=GlobalSign Root CA, C=EN" with most extensions missing, and no chain.
But as to the PCAPs:
See line 3638 in the fail log, the raw read bytes is different to the first five bytes of Transport Layer Security in the server hello response. In success log, they are the same.
That's not the only difference. Although the time matches,
your fail.PCAP doesn't match your fail.txt at all. Most importantly, it doesn't fail --
it receives the correct cert chain (Let's Encrypt + DST) and completes the handshake successfully.
In more detail:
the ClientHello is very different. It offers max TLS1.2, not TLS1.3 as offered by (your) Java.
It has a different list of ciphersuites, and different extensions (necessarily so for 1.2 vs 1.3),
among which are Heartbeat and ticket neither of which Java supports.
the ServerHello is shorter (record header 16 03 03 00 45 vs 16 03 03 00 59 in the fail.txt or 16 03 03 00 65 in the success.txt,
as you noticed) because it offered ticket and the server agreed, and thus the server does not provide a session-id.
(as above) it gets the good certs, as well as CertStatus ServerKX ServerDone,
and proceeds to send ClientKX CCS Finished and receive ticket CCS Finished -- i.e. success.
your client soon (but not instantly) RSTs without sending (or receiving) any data; this is the behavior of a Windows program that closes without doing shutdown (perhaps due to being killed) or a Unix program that explicitly sets linger=0 (which is unusual).
I also notice the fail.PCAP connection goes to 151.101.65.69 but the success.PCAP goes to 151.101.193.69.
Both of those addresses (and two others) are valid for stackoverflow.com, but usually connections
from the same machine within a short time window like this would resolve to and use the same address.
Look carefully at what you did for the fail.PCAP and see if you can get a PCAP that actually is a failure case.
Actually, an idea occurs here. DO YOU HAVE AN ANTIVIRUS OR OTHER 'ENDPOINT PROTECTION'? That might intercept the outgoing connection before it leaves your machine, so that the program (Java) sees the bogus cert even though the correct cert was actually fetched from the network. But there would still need to be a reason it intercepts one connection and not another.

Where does InstallCert.java get the server certificates

I'm attempting to follow the instructions on this page:
http://www.mkyong.com/webservices/jax-ws/suncertpathbuilderexception-unable-to-find-valid-certification-path-to-requested-target/
to create a certificate for my localhost in which to do some development testing.
When running InstallCert for localhost:8443, the following two certificates are generated:
Server sent 2 certificate(s):
1 Subject CN=localhost4.localdomain4, O=example.com, C=US
Issuer CN=Certificate Shack, O=example.com, C=US
sha1 f4 2a a9 09 32 a6 ee 41 9d 9c 44 e6 4a bc 31 79 17 cb 88 fd
md5 e0 78 65 83 30 33 78 c5 80 17 e7 7a a2 91 85 52
2 Subject CN=Certificate Shack, O=example.com, C=US
Issuer CN=Certificate Shack, O=example.com, C=US
sha1 b8 87 d6 2d ac d8 36 06 7c 58 68 10 3e 21 39 6a a0 33 a1 25
md5 07 24 57 5f f8 35 1e 97 70 ff 54 aa 13 e6 6b 12
The trouble is that my system needs the CN to be localhost. I have no idea where the localhost4.localdomain4 comes from. How can I change this to be simply localhost?
The certificate comes from the server, during the handshake.
The CN is inside the certificate.
You can't change it without creating a new server certificate.

Getting EOFException error while establishing a SSL connection

I’m writing a program in java that send official invoice information to the Fiscal Administration. This public service provided certificates to use in the SSL connection to the web services and to encrypt some especial data fields inside the request body message.
I’m having an EOFException error during the handshake phase after client and server have agreed to communicate using the agreed cipher suite that in this case is TLS_RSA_WITH_AES_128_CBC_SHA.
Following the SSL protocol the client perform with success a test using the new cipher and send the test data to the server so the server can also repeat the same test and confirm that it is also capable of encrypt and decrypt data. And in this point the server send the EOFException.
Here is the last part of the SSL communication log:
Send a quick confirmation to the server verifying that we know the private key corresponding to the client certificate we just sent...
* CertificateVerify
[write] MD5 and SHA1 hashes: len = 262
binary data here too large not displayed
main, WRITE: TLSv1 Handshake, length = 262
[Raw write]: length = 267
binary data here too large not displayed
*Tell the server we're changing to the newly established cipher suite. All further messages will be encrypted using the parameters we just established. *
main, WRITE: TLSv1 Change Cipher Spec, length = 1
[Raw write]: length = 6
0000: 14 03 01 00 01 01
... and finishes with success
..Finished
We send an encrypted Finished message to verify everything worked.
verify_data: { 221, 96, 47, 110, 19, 170, 244, 8, 37, 152, 160, 40 }
...
The client encrypt the test data..
[write] MD5 and SHA1 hashes: len = 16
0000: 14 00 00 0C DD 60 2F 6E 13 AA F4 08 25 98 A0 28 .....`/n....%..(
Padded plaintext before ENCRYPTION: len = 48
0000: 14 00 00 0C DD 60 2F 6E 13 AA F4 08 25 98 A0 28 .....`/n....%..(
0010: 10 7F 85 11 EC 6D 5D ED 21 70 27 F4 DC 23 C0 9B .....m].!p'..#..
0020: A7 6F C2 80 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B .o..............
main, WRITE: TLSv1 Handshake, length = 48
* ...and send the test data to the server so that the server can do the same test and confirm that encrypted communication can be established (53 bytes = 48 from the test data + 5 from header) *
[Raw write]: length = 53
0000: 16 03 01 00 30 1C 17 08 0F 49 C9 6A 7A 8B 8C 48 ....0....I.jz..H
0010: BA 57 2D CB 06 46 1E 65 61 7C 5F 74 F2 08 AB 12 .W-..F.ea._t....
0020: 91 47 72 8C 8F 84 0A CB D7 29 E2 FD 84 B2 FD 9E .Gr......)......
0030: 47 DC 13 60 B4 G..`.
...and the server respond with the EOFException error
main, received EOFException: error
main, handling exception: javax.net.ssl.SSLHandshakeException: Remote host closed
connection during handshake
%% Invalidated: [Session-1, TLS_RSA_WITH_AES_128_CBC_SHA]
main, SEND TLSv1 ALERT: fatal, description = handshake_failure
Padded plaintext before ENCRYPTION: len = 32
0000: 02 28 BC 65 1A CA 68 87 79 84 5F 64 16 F5 28 72 .(.e..h.y._d..(r
0010: F7 8A 69 72 93 D8 09 09 09 09 09 09 09 09 09 09 ..ir............
main, WRITE: TLSv1 Alert, length = 32
[Raw write]: length = 37
0000: 15 03 01 00 20 0D 9A 35 18 B7 98 4B 7B AF 82 4E .... ..5...K...N
0010: 1A EE 7D AC 5D D5 49 05 4E 74 B9 77 E4 CD 87 61 ....].I.Nt.w...a
0020: 23 03 5C 9C 7E #...
main, called closeSocket()
main, called close()
main, called closeInternal(true)
I have no idea on what might be the cause for such a failure and how to programmatically influence the outcome of this step in the process. I’ve tried force the use of other ciphers recognized by both client and server such as SSL_RSA_WITH_RC4_128_MD5 but the error remain.
Any thoughts on how to solve this problem?
Any thoughts on how to solve this problem?
I suggest that you get in contact with the people who run that service, and get them to look at their logs to see why their server is closing the connection during SSL setup.
(Strictly speaking, the server does not "respond with [an] EOFException error". It is actually closing the TCP connection and the client-side Java libraries are throwing the exception. You are likely to get a more helpful response from the maintainers of the service if you use correct terminology.)

Categories

Resources