HTTPSender Unable to sendViaGet to url[https://myserver/context]
javax.net.ssl.SSLPeerUnverifiedException: SSL peer failed hostname validation for name: null
at org.opensaml.ws.soap.client.http.TLSProtocolSocketFactory.verifyHostname(TLSProtocolSocketFactory.java:233)
at org.opensaml.ws.soap.client.http.TLSProtocolSocketFactory.createSocket(TLSProtocolSocketFactory.java:186)
Zkusil jsem spustit znovu s parametrem
-Djdk.internal.httpclient.disableHostnameVerification=true
a následovala výjimka:
HTTPSender Unable to sendViaGet to url[https://myserver/context]
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at sun.security.ssl.SSLSessionImpl.getPeerCertificates(Unknown Source)
at org.apache.commons.httpclient.protocol.SSLProtocolSocketFactory.verifyHostName(SSLProtocolSocketFactory.java:276)
Pokud byl request proveden pomocí curl, tak fungoval
curl -X GET --cacert /C/certs/root_cert.cer 'https://myserver/context
' -H 'Authorization: Basic QVBJOk1vbmV0YTIwMjA=' -v
Zkusil jsem openssl
OpenSSL> s_client -connect myserver:443
Loading 'screen' into random state - done
CONNECTED(000008C0)
write:errno=10054
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 317 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
---
error in s_client
Zde je vidět, že server nevrátil certifikát.Zkusil jsem znovu s parametrem -servername
openssl s_client -connect myserver:443 -servername myserver
Také je vhodné ověřit, že server podporuje TLSv1.2:
openssl s_client -connect myserver:443 -tls1_2 -servername myserver
V obou případech bylo vidět, že server certifikát vrací. Parametr -servername nastavuje TLS SNI (Server Name Indication) extension v ClientHello message během handshake, jak je popsáno v dokumentaci.
Při následném prohlédnutí ClientHello zprávy pomocí wiresharku bylo patrné, že neobsahuje server_name extension (více o tématu zde). Tato je pro některé servery nutná (i když dle RFC6066 nepovinná) - jeden webový server může sloužit více doménám a jaký certifikát použít se rozhoduje právě na základě obsahu server_name.
V javě lze vypnout nebo povolit (defaultní stav) SNI pomocí parametru
-Djsse.enableSNIExtension=true
Naštěstí jsem narazil na informaci, že Java nastavuje extension server_name pouze pro FQDN, což myserver není (podobně jako např. localhost).
Pokud tedy chceme z javy volat server, který v handshake protokolu Client Hello vyžaduje extension server_name, je třeba aby tento měl FQDN a samozřejmě odpovídající certifikát, který máme umístěn i v našem truststore.
Žádné komentáře:
Okomentovat