Context
I’m attempting to create an SSLEngine that will validate that the subject alternate name is correct for the certificate returned by the server. I understand that java does not do this automatically and must be asked to do this. I’ve set up my SSLEngine as follows
//this keystore will provide client certificates, an optional part of TLS to identify the client. KeyStore personalKS = KeyStore.getInstance( "Windows-MY" ); //$NON-NLS-1$ personalKS.load( null, null ); KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance( KeyManagerFactory.getDefaultAlgorithm() ); keyManagerFactory.init( personalKS, null ); SSLContext context = SSLContext.getInstance( "TLSv1.3" ); SSLParameters sslParams = new SSLParameters(); sslParams.setEndpointIdentificationAlgorithm("HTTPS"); context.init( keyManagerFactory.getKeyManagers(), null, null ); SSLEngine sslEngine = context.createSSLEngine(); sslEngine.setSSLParameters( sslParams ); return sslEngine;
Without the line sslParams.setEndpointIdentificationAlgorithm("HTTPS");
the connection succeeds for any valid signed certificate (even if its subject alternate name is incorrect).
However once I add that line I get an exception
com.mirada.data.dicom.network.base.AssociationFailedException: Failed to connect at com.mirada.data.dicom.network.ServerAssociationConnector.waitForImpl(ServerAssociationConnector.java:328) at com.mirada.data.dicom.network.ServerAssociationConnector.waitFor(ServerAssociationConnector.java:183) at com.mirada.fusionxd.export.configuration.DicomConfigurationPage$ScpDialog$4.actionPerformed(DicomConfigurationPage.java:701) at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1967) at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2308) at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405) at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262) at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:279) at java.desktop/java.awt.Component.processMouseEvent(Component.java:6632) at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3342) at java.desktop/java.awt.Component.processEvent(Component.java:6397) at java.desktop/java.awt.Container.processEvent(Container.java:2263) at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5008) at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4840) at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918) at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547) at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488) at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307) at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2772) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4840) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:772) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:743) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:117) at java.desktop/java.awt.WaitDispatchSupport$2.run(WaitDispatchSupport.java:190) at java.desktop/java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:235) at java.desktop/java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:233) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.desktop/java.awt.WaitDispatchSupport.enter(WaitDispatchSupport.java:233) at java.desktop/java.awt.Dialog.show(Dialog.java:1070) at java.desktop/java.awt.Component.show(Component.java:1716) at java.desktop/java.awt.Component.setVisible(Component.java:1663) at java.desktop/java.awt.Window.setVisible(Window.java:1031) at java.desktop/java.awt.Dialog.setVisible(Dialog.java:1005) at com.mirada.fusionxd.export.configuration.DicomConfigurationPage$4.actionPerformed(DicomConfigurationPage.java:319) at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1967) at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2308) at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405) at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262) at java.desktop/javax.swing.AbstractButton.doClick(AbstractButton.java:369) at java.desktop/javax.swing.AbstractButton.doClick(AbstractButton.java:349) at com.mirada.fusionxd.export.configuration.DicomConfigurationPage$1.mouseClicked(DicomConfigurationPage.java:248) at java.desktop/java.awt.AWTEventMulticaster.mouseClicked(AWTEventMulticaster.java:278) at java.desktop/java.awt.Component.processMouseEvent(Component.java:6635) at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3342) at java.desktop/java.awt.Component.processEvent(Component.java:6397) at java.desktop/java.awt.Container.processEvent(Container.java:2263) at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5008) at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4840) at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918) at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4556) at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488) at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307) at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2772) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4840) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:772) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:743) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:117) at java.desktop/java.awt.WaitDispatchSupport$2.run(WaitDispatchSupport.java:190) at java.desktop/java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:235) at java.desktop/java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:233) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.desktop/java.awt.WaitDispatchSupport.enter(WaitDispatchSupport.java:233) at java.desktop/java.awt.Dialog.show(Dialog.java:1070) at java.desktop/java.awt.Component.show(Component.java:1716) at java.desktop/java.awt.Component.setVisible(Component.java:1663) at java.desktop/java.awt.Window.setVisible(Window.java:1031) at java.desktop/java.awt.Dialog.setVisible(Dialog.java:1005) at com.mirada.platform.core.ui.dialog.DialogUi.show(DialogUi.java:104) at com.mirada.platform.core.ui.dialog.StandardDialog.show(StandardDialog.java:171) at com.mirada.platform.core.ui.configuration.ConfigurationPageDialog.show(ConfigurationPageDialog.java:227) at com.mirada.fusionxd.application.action.PreferencesDialogAction.actionPerformed(PreferencesDialogAction.java:51) at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1967) at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2308) at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405) at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262) at java.desktop/javax.swing.AbstractButton.doClick(AbstractButton.java:369) at java.desktop/javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:1020) at java.desktop/javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(BasicMenuItemUI.java:1064) at java.desktop/java.awt.Component.processMouseEvent(Component.java:6632) at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3342) at java.desktop/java.awt.Component.processEvent(Component.java:6397) at java.desktop/java.awt.Container.processEvent(Container.java:2263) at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5008) at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4840) at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918) at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547) at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488) at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307) at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2772) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4840) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:772) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:743) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90) Caused by: java.util.concurrent.ExecutionException: java.io.IOException at com.google.common.util.concurrent.AbstractFuture.getDoneValue(AbstractFuture.java:531) at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:512) at com.google.common.util.concurrent.AbstractFuture$TrustedFuture.get(AbstractFuture.java:83) at com.mirada.data.dicom.network.AssociationEventHandler.get(AssociationEventHandler.java:104) at com.mirada.data.dicom.network.AssociationEventHandler.get(AssociationEventHandler.java:1) at com.mirada.data.dicom.network.ServerAssociationConnector.waitForImpl(ServerAssociationConnector.java:315) ... 131 more Caused by: java.io.IOException at com.mirada.data.dicom.network.base.StateMachine.threadEntry(StateMachine.java:655) at com.mirada.data.dicom.network.base.StateMachine.lambda$0(StateMachine.java:187) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834) Caused by: java.lang.NullPointerException at java.base/sun.net.util.IPAddressUtil.textToNumericFormatV4(IPAddressUtil.java:49) at java.base/sun.net.util.IPAddressUtil.isIPv4LiteralAddress(IPAddressUtil.java:241) at java.base/sun.security.util.HostnameChecker.isIpAddress(HostnameChecker.java:117) at java.base/sun.security.util.HostnameChecker.match(HostnameChecker.java:95) at java.base/sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:459) at java.base/sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:434) at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:291) at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:141) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1307) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1204) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1151) at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392) at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:444) at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1065) at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1052) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:999) at com.mirada.data.dicom.network.base.StateMachine.readFromSocket(StateMachine.java:839) at com.mirada.data.dicom.network.base.StateMachine.readNext(StateMachine.java:747) at com.mirada.data.dicom.network.base.StateMachine.threadEntry(StateMachine.java:582) ... 5 more
Interestingly, debugging whats going on within HostNameChecker#match shows that the X509Certificate doesn’t have any subject alternate names. But the toString representation of it does.
These are internal network certificates created by me, signed by a local root CA, so its very possibly I’ve created the certificates wrong
Question
How should I be setting up an sslEngine to validate the domain name as well as the certificate validation? Why am I getting this null pointer exception?
Answer
Looks like the problem was that in hostname checker the “expected name” was to be supplied by me, not as I had imagined based on the URL I was connecting to.
The correct way for me to create the SSL engine was as follows
SSLEngine sslEngine = context.createSSLEngine(hostname, port);
It is up to my code to know what host and port I expect to be communicating with (which luckily I do in my case)