Nick created ZOOKEEPER-5096:
-------------------------------

             Summary: Quorum TLS fails to form a quorum in 3.9.6 (fips-enabled, 
default)
                 Key: ZOOKEEPER-5096
                 URL: https://issues.apache.org/jira/browse/ZOOKEEPER-5096
             Project: ZooKeeper
          Issue Type: Bug
          Components: security
    Affects Versions: 3.9.6
         Environment: Observed on Temurin 21.0.12.1+1.
            Reporter: Nick


A recent commit 
[8b4266550|https://github.com/apache/zookeeper/commit/8b4266550dbac68fd27586c023bbaa714f9f0754]
 for fixing a CVE:
"Quorum TLS in FIPS mode accepts hostname-mismatched peer certificates", added
{{SSLParameters.setEndpointIdentificationAlgorithm("HTTPS")}} to _both_ 
directions of
quorum TLS in FIPS mode.

 SunJSSE (X509TrustManagerImpl) only matches a _client_ certificate against the 
peer IP (no reverse DNS lookup to check DNS Subject/SANs like ZKTrustManager 
does for non-FIPS mode).

We have client certificates that are issued before the IP is known (in 
Kubernetes), and so we can only use DNS names for verification.

Without additional logging, it appears like this:

On the accepting peer (the quorum TLS server):

{noformat}
INFO  o.a.z.s.q.QuorumCnxManager$Listener$ListenerHandler@1073 - Received 
connection request from /10.0.0.15:33280
INFO  o.a.z.s.q.UnifiedServerSocket$UnifiedSocket@266 - Accepted TLS connection 
from /10.0.0.15:33280 - NONE - SSL_NULL_WITH_NULL_NULL
WARN  o.a.z.s.q.QuorumCnxManager@627 - Exception reading or writing challenge
java.net.SocketException: Socket is closed
    at java.base/sun.security.ssl.SSLSocketImpl.getInputStream(Unknown Source)
    at 
o.a.z.s.q.UnifiedServerSocket$UnifiedInputStream.getRealInputStream(UnifiedServerSocket.java:699)
    at o.a.z.s.q.QuorumCnxManager.handleConnection(QuorumCnxManager.java:599)
{noformat}

on the client (quorum TLS client):

{noformat}
WARN  o.a.z.s.q.QuorumCnxManager@398 - Cannot open channel to 10 at election 
address <peer>:3888
javax.net.ssl.SSLHandshakeException: (certificate_unknown) Received fatal 
alert: certificate_unknown
    at o.a.z.s.q.QuorumCnxManager.initiateConnection(QuorumCnxManager.java:384)
{noformat}

It is a little more obvious when run with {{-Djavax.net.debug=ssl:handshake}}

{noformat}
javax.net.ssl|ERROR|...|Fatal (CERTIFICATE_UNKNOWN): Endpoint Identification 
Algorithm HTTPS is not supported on the server side
"throwable" : {
  java.security.cert.CertificateException: Endpoint Identification Algorithm 
HTTPS is not supported on the server side
      at java.base/sun.security.ssl.X509TrustManagerImpl.checkIdentity(Unknown 
Source)
      at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown 
Source)
      at 
java.base/sun.security.ssl.X509TrustManagerImpl.checkClientTrusted(Unknown 
Source)
      at 
java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkClientCerts(Unknown
 Source)
      at 
java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(Unknown
 Source)
{noformat}

and we then see no IP SANs to match on:

{noformat}
ObjectId: 2.5.29.17 Criticality=true
SubjectAlternativeName [
  DNSName: <sts>-headless.<namespace>.svc.cluster.local
  DNSName: <sts>-0.<sts>-headless.<namespace>.svc.cluster.local
]
{noformat}

[HostnameChecker.matchIP|https://github.com/openjdk/jdk21u/blob/master/src/java.base/share/classes/sun/security/util/HostnameChecker.java]
 only compares against {{ALTNAME_IP}} SANs and never DNS SANs.

h2. Current workaround

Revert back to pre-3.9.6 behaviour of no checking for the client certificate 
(server name verification will still be performed).

{noformat}
ssl.quorum.clientHostnameVerification=false
{noformat}

or disabling {{fips-enabled=false}}, though this was causing me other issues 
with metric scraping (I didn't dive deep into that yet).



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to