Connecting to MongoDB using SSL, but without locally installed server SSL certificate

The problem:

MongoClientOptions options=MongoClientOptions.builder().sslEnabled(true).sslInvalidHostNameAllowed(true).build();
MongoClient mongoClient = new MongoClient("servermongodb.server.tralala:27017",options);
... = mongoClient.getDatabase("lot_of_data_here");

… does this…

INFO: Exception in monitor thread while connecting to servermongodb.server.tralala:27017
com.mongodb.MongoSocketWriteException: Exception sending message
	at com.mongodb.connection.InternalStreamConnection.translateWriteException(InternalStreamConnection.java:462)
	at com.mongodb.connection.InternalStreamConnection.sendMessage(InternalStreamConnection.java:205)
	at com.mongodb.connection.CommandHelper.sendMessage(CommandHelper.java:89)
	at com.mongodb.connection.CommandHelper.executeCommand(CommandHelper.java:32)
	at com.mongodb.connection.InternalStreamConnectionInitializer.initializeConnectionDescription(InternalStreamConnectionInitializer.java:83)
	at com.mongodb.connection.InternalStreamConnectionInitializer.initialize(InternalStreamConnectionInitializer.java:43)
	at com.mongodb.connection.InternalStreamConnection.open(InternalStreamConnection.java:115)
	at com.mongodb.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:128)
	at java.lang.Thread.run(Thread.java:745)
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
	at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
	at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
	at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
	at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
	at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:747)
	at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
	at com.mongodb.connection.SocketStream.write(SocketStream.java:75)
	at com.mongodb.connection.InternalStreamConnection.sendMessage(InternalStreamConnection.java:201)
	... 7 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
	at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
	at sun.security.validator.Validator.validate(Validator.java:260)
	at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
	at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
	at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1491)
	... 16 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
	at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
	at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
	... 22 more

.

If you do not need serious SSL server authentication and use SSL “only” for transfer encryption because you have learned that “Trusted Networks (TM)” do not exist, then you will find this helpful to avoid hacking JVM certificate chains and key bundles. Note that you should use this only if you know what you are doing here, as usual when playing with security things… :)

TrustManager[] trustManagers=new TrustManager[] {
    new X509TrustManager() {
        public X509Certificate[] getAcceptedIssuers() { return null; }
        public void checkClientTrusted(X509Certificate[] certs, String t) { }
        public void checkServerTrusted(X509Certificate[] certs, String t) { }
    }
};

SSLContext sslContext=SSLContext.getInstance("TLS");
sslContext.init(null,trustManagers,new SecureRandom());

// Note: the order is of importance as "sslEnabled()" (wrongly) sets the 
// socket factory to default
MongoClientOptions options=MongoClientOptions.builder().
                sslEnabled(true).
                sslInvalidHostNameAllowed(true).
                socketFactory(sslContext.getSocketFactory()).
                build();

MongoClient mongoClient = new MongoClient(uri,options);
... = mongoClient.getDatabase("i_see_documents");

Leave a Reply

Your email address will not be published. Required fields are marked *