java.security.cert.CertificateException: No name matching couchbase found when upgrading from Java SDK 2.7.11 to 3.2.4

I encountered the following error when I updated from Couchbase Java SDK 2.7.11 to 3.2.4.

2022-01-10 15:24:35.406  WARN [servce-name,,,] 1 --- [      cb-events] com.couchbase.endpoint                   : [com.couchbase.endpoint][EndpointConnectionFailedEvent][4230ms] Connect attempt 19 failed because of DecoderException: javax.net.ssl.SSLHandshakeException: No name matching couchbase found {"circuitBreaker":"DISABLED","coreId":"0x7dd5f40800000001","remote":"couchbase:11207","type":"KV"}
com.couchbase.client.core.deps.io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: No name matching couchbase found
at java.base/java.lang.Thread.run(Thread.java:829) ~[na:na]
Caused by: javax.net.ssl.SSLHandshakeException: No name matching couchbase found
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131) ~[na:na]
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:349) ~[na:na]
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:292) ~[na:na]
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:287) ~[na:na]
at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1357) ~[na:na]
at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1232) ~[na:na]
at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1175) ~[na:na]
at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392) ~[na:na]
at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443) ~[na:na]
at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1074) ~[na:na]
at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1061) ~[na:na]
at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:1008) ~[na:na]
... 1 common frames omitted
Caused by: java.security.cert.CertificateException: No name matching couchbase found
at java.base/sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:234) ~[na:na]
at java.base/sun.security.util.HostnameChecker.match(HostnameChecker.java:103) ~[na:na]
at java.base/sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:455) ~[na:na]
at java.base/sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:429) ~[na:na]
at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:283) ~[na:na]
at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:141) ~[na:na]
at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1335) ~[na:na]
... 9 common frames omitted

The update works fine when connecting without TLS

@Bean
  public Cluster cluster(CouchbaseProperties properties) {
    return Cluster.connect(
        properties.getBootstrapHosts().stream().collect(Collectors.joining(",")),
        properties.getBucket().getUsername(),
        properties.getBucket().getPassword()
    );
  }

but I get the error when I attempt to connect using a self signed certificate that I created following

 @Bean(destroyMethod = "shutdown")
  public ClusterEnvironment clusterEnvironment(CouchbaseProperties properties) {
    Path tlsKeyStorePath = Paths.get(properties.getTlsKeystore().getLocation());
    log.info("Enabling TLS for all client/server couchbase communication using TLS Keystore: {}",
        tlsKeyStorePath);
    return ClusterEnvironment.builder()
        .securityConfig(SecurityConfig
            .enableTls(true)
            .trustStore(
                tlsKeyStorePath,
                properties.getTlsKeystore().getPassword(),
                Optional.empty()
            )
        )
        .timeoutConfig(TimeoutConfig.builder()
            .connectTimeout(properties.getConnectTimeout())
        )
        .build();
  }

  @Bean(destroyMethod = "disconnect")
  public Cluster cluster(CouchbaseProperties properties, ClusterEnvironment clusterEnvironment) {

    // List of cluster nodes, separated by commas
    String connectionString = properties.getBootstrapHosts().stream().collect(Collectors.joining(","));
    log.info("Connecting to couchbase cluster using connection string: {}", connectionString);

    Path tlsKeyStorePath = Paths.get(properties.getTlsKeystore().getLocation());
    log.info("Authenticating couchbase connecting using certificate from TLS keystore: {}",
        tlsKeyStorePath);

    ClusterOptions clusterOptions = ClusterOptions
        .clusterOptions(CertificateAuthenticator.fromKeyStore(
            tlsKeyStorePath,
            properties.getTlsKeystore().getPassword(),
            Optional.empty()))
        .environment(clusterEnvironment);

    return Cluster.connect(connectionString, clusterOptions);
  }

Any advice would be apprecated.

@Lewis_Watson SDK 3 by default performs hostname validation where SDK 2 did not. Just to check, can you disable hostname validation via enableHostnameVerification(false) and see if this solves the issue?

Note that if it solves the issue you are at the same security level as with SDK 2, but you should fix the hostnames in your certificates and enable it again for higher security with your TLS/cert setup.

Thanks @daschl, certificate hostname was indeed the problem. I didn’t quite understand before, but the error message was attempting to tell me that the certificate needed to specify a “couchbase” hostname since thats what I called the couchbase service in my docker-compose file.

Changing step 7 in Configure Server Certificates | Couchbase Docs to be

cp ./server.ext ./server.ext.tmp

echo "subjectAltName = DNS:couchbase" \
>> ./server.ext.tmp

Got me a bit further. I’m now seeing timeout warnings:

2022-01-11 16:01:29.789  WARN [service-name,,,] 1 --- [      cb-events] com.couchbase.endpoint                   : [com.couchbase.endpoint][EndpointConnectionFailedEvent][5000ms] Connect attempt 2 failed because of TimeoutException: Did not observe any item or terminal signal within 5000ms in 'lift' (and no fallback has been configured) {"bucket":"data","circuitBreaker":"DISABLED","coreId":"0x3d113f7200000001","remote":"couchbase:11207","type":"KV"}

java.util.concurrent.TimeoutException: Did not observe any item or terminal signal within 5000ms in 'lift' (and no fallback has been configured)
at reactor.core.publisher.FluxTimeout$TimeoutMainSubscriber.handleTimeout(FluxTimeout.java:289) ~[reactor-core-3.3.4.RELEASE.jar!/:3.3.4.RELEASE]
at reactor.core.publisher.FluxTimeout$TimeoutMainSubscriber.doTimeout(FluxTimeout.java:274) ~[reactor-core-3.3.4.RELEASE.jar!/:3.3.4.RELEASE]
at reactor.core.publisher.FluxTimeout$TimeoutTimeoutSubscriber.onNext(FluxTimeout.java:396) ~[reactor-core-3.3.4.RELEASE.jar!/:3.3.4.RELEASE]
at reactor.core.publisher.StrictSubscriber.onNext(StrictSubscriber.java:89) ~[reactor-core-3.3.4.RELEASE.jar!/:3.3.4.RELEASE]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:73) ~[reactor-core-3.3.4.RELEASE.jar!/:3.3.4.RELEASE]
at reactor.core.publisher.MonoDelay$MonoDelayRunnable.run(MonoDelay.java:117) ~[reactor-core-3.3.4.RELEASE.jar!/:3.3.4.RELEASE]
at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:68) ~[reactor-core-3.3.4.RELEASE.jar!/:3.3.4.RELEASE]
at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:28) ~[reactor-core-3.3.4.RELEASE.jar!/:3.3.4.RELEASE]
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:829) ~[na:na]

@Lewis_Watson are you sure that all ports are properly exposed? So not only the non-tls ports, but also the tls ones. It is trying to connect to

couchbase:11207

but looks like it can’t reach the socket?

Thanks @daschl. My java client application and couchbase are both running via docker-compose on a shared network, so all ports are available to the java client application via the couchbase hostname. I’ll keep digging though.

Debugging docker-compose files is a bit out of scope for a couchbase forum, but for reference this is simplified version of what my docker-compose.yaml file looks like

version: '3.5'
networks:
  app-tier:
    name: 'app-tier'
    driver: bridge
services:
  couchbase:
    container_name: couchbase
    image: couchbase:enterprise-6.5.0
    networks:
      - app-tier
    ports:
      - '8091-8096:8091-8096'
      - '11207-11211:11207-11211'
    volumes:
      - './couchbase-cert/servercertfiles/public/chain.pem:/opt/couchbase/var/lib/couchbase/inbox/chain.pem'
      - './couchbase-cert/servercertfiles/private/pkey.key:/opt/couchbase/var/lib/couchbase/inbox/pkey.key'
  java-client-app:
    container_name: java-client-app
    build: ..
    networks:
      - app-tier
    ports:
      - '8080:8080'
      - '8003:8003'
    depends_on:
      - couchbase
    environment:
      - COUCHBASE_BOOTSTRAP-HOSTS=couchbase
      - COUCHBASE_TLS-KEYSTORE_LOCATION=/couchbase-cert/my.keystore
      - COUCHBASE_TLS-KEYSTORE_PASSWORD=storepass
    volumes:
      - './couchbase-cert/servercertfiles/javaclient/my.keystore:/couchbase-cert/my.keystore'

@Lewis_Watson can you enable debug logging and share the full log with me? Happy also via direct message in case you don’t want to share it publicly.

I’ve created a standalone github repository that reproduces the behaviour. GitHub - LewisWatson/java-couchbase-tls

I’ve also included debug output as requested java-couchbase-tls/debug.log at main · LewisWatson/java-couchbase-tls · GitHub