You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by or...@apache.org on 2021/06/13 21:17:13 UTC

[qpid-broker-j] 01/02: QPID-8535:[Broker-J]Add flag to ignore invlaid SNI header

This is an automated email from the ASF dual-hosted git repository.

orudyy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git

commit 0dff63caf991dfa72fcb4d2989a9427490228a08
Author: Dedeepya T <de...@yahoo.co.in>
AuthorDate: Tue Jun 8 19:29:58 2021 +0530

    QPID-8535:[Broker-J]Add flag to ignore invlaid SNI header
    
    This closes #91
---
 .../apache/qpid/server/model/port/AmqpPort.java    |  9 +++++
 .../qpid/server/model/port/AmqpPortImpl.java       |  9 +++++
 .../NonBlockingConnectionTLSDelegate.java          | 29 +++++++++++++--
 .../org/apache/qpid/server/transport/SNITest.java  | 42 +++++++++++++++-------
 ...nectionPrincipalStatisticsRegistryImplTest.java |  2 ++
 5 files changed, 76 insertions(+), 15 deletions(-)

diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java b/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java
index 530d603..68f5683 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java
@@ -64,6 +64,12 @@ public interface AmqpPort<X extends AmqpPort<X>> extends Port<X>
     @ManagedContextDefault(name = PORT_MAX_OPEN_CONNECTIONS)
     int DEFAULT_MAX_OPEN_CONNECTIONS = -1;
 
+    String PORT_IGNORE_INVALID_SNI = "qpid.port.amqp.ignoreInvalidSni";
+
+    @SuppressWarnings("unused")
+    @ManagedContextDefault(name = PORT_IGNORE_INVALID_SNI)
+    boolean DEFAULT_PORT_IGNORE_INVALID_SNI = false;
+
     @SuppressWarnings("unused")
     @ManagedContextDefault( name = PORT_AMQP_THREAD_POOL_SIZE)
     long DEFAULT_PORT_AMQP_THREAD_POOL_SIZE = 8;
@@ -159,6 +165,9 @@ public interface AmqpPort<X extends AmqpPort<X>> extends Port<X>
     @ManagedAttribute( defaultValue = "${" + PORT_MAX_OPEN_CONNECTIONS + "}" )
     int getMaxOpenConnections();
 
+    @ManagedAttribute( defaultValue = "${" + PORT_IGNORE_INVALID_SNI + "}" )
+    boolean getIgnoreInvalidSni();
+
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.COUNT,
             label = "Open Connections",
             description = "Current number of connections made through this port",
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java b/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java
index 88fc19c..bd7981a 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java
@@ -86,6 +86,9 @@ public class AmqpPortImpl extends AbstractPort<AmqpPortImpl> implements AmqpPort
     private int _maxOpenConnections;
 
     @ManagedAttributeField
+    private boolean _ignoreInvalidSni;
+
+    @ManagedAttributeField
     private int _threadPoolSize;
 
     @ManagedAttributeField
@@ -149,6 +152,12 @@ public class AmqpPortImpl extends AbstractPort<AmqpPortImpl> implements AmqpPort
     }
 
     @Override
+    public boolean getIgnoreInvalidSni()
+    {
+        return _ignoreInvalidSni;
+    }
+
+    @Override
     protected void onCreate()
     {
         super.onCreate();
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnectionTLSDelegate.java b/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnectionTLSDelegate.java
index a463af0..b646d10 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnectionTLSDelegate.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnectionTLSDelegate.java
@@ -43,6 +43,7 @@ import org.slf4j.LoggerFactory;
 import org.apache.qpid.server.bytebuffer.QpidByteBuffer;
 import org.apache.qpid.server.model.port.AmqpPort;
 import org.apache.qpid.server.transport.network.security.ssl.SSLUtil;
+import org.apache.qpid.server.util.ConnectionScopedRuntimeException;
 import org.apache.qpid.server.util.ServerScopedRuntimeException;
 
 public class NonBlockingConnectionTLSDelegate implements NonBlockingConnectionDelegate
@@ -61,6 +62,7 @@ public class NonBlockingConnectionTLSDelegate implements NonBlockingConnectionDe
     private QpidByteBuffer _netInputBuffer;
     private QpidByteBuffer _netOutputBuffer;
     private QpidByteBuffer _applicationBuffer;
+    private final boolean _ignoreInvalidSni;
 
 
     public NonBlockingConnectionTLSDelegate(NonBlockingConnection parent, AmqpPort port)
@@ -79,6 +81,7 @@ public class NonBlockingConnectionTLSDelegate implements NonBlockingConnectionDe
         _netInputBuffer = QpidByteBuffer.allocateDirect(_networkBufferSize);
         _applicationBuffer = QpidByteBuffer.allocateDirect(_networkBufferSize);
         _netOutputBuffer = QpidByteBuffer.allocateDirect(_networkBufferSize);
+        _ignoreInvalidSni = port.getIgnoreInvalidSni();
     }
 
     @Override
@@ -97,12 +100,12 @@ public class NonBlockingConnectionTLSDelegate implements NonBlockingConnectionDe
                 buffer.flip();
                 if (SSLUtil.isSufficientToDetermineClientSNIHost(buffer))
                 {
-                    String hostName = SSLUtil.getServerNameFromTLSClientHello(buffer);
+                    final SNIHostName hostName = getSNIHostName(buffer);
                     if (hostName != null)
                     {
-                        _parent.setSelectedHost(hostName);
+                        _parent.setSelectedHost(hostName.getAsciiName());
                         SSLParameters sslParameters = _sslEngine.getSSLParameters();
-                        sslParameters.setServerNames(Collections.singletonList(SSLUtil.createSNIHostName(hostName)));
+                        sslParameters.setServerNames(Collections.singletonList(hostName));
                         _sslEngine.setSSLParameters(sslParameters);
                     }
                     _hostChecked = true;
@@ -156,6 +159,26 @@ public class NonBlockingConnectionTLSDelegate implements NonBlockingConnectionDe
         return readData;
     }
 
+    private SNIHostName getSNIHostName(final QpidByteBuffer buffer)
+    {
+        try
+        {
+            final String name = SSLUtil.getServerNameFromTLSClientHello(buffer);
+            if (name != null)
+            {
+                return SSLUtil.createSNIHostName(name);
+            }
+        }
+        catch (ConnectionScopedRuntimeException e)
+        {
+            if (!_ignoreInvalidSni)
+            {
+                throw e;
+            }
+        }
+        return null;
+    }
+
     @Override
     public WriteResult doWrite(Collection<QpidByteBuffer> buffers) throws IOException
     {
diff --git a/broker-core/src/test/java/org/apache/qpid/server/transport/SNITest.java b/broker-core/src/test/java/org/apache/qpid/server/transport/SNITest.java
index e567573..f9c8eac 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/transport/SNITest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/transport/SNITest.java
@@ -24,6 +24,7 @@ import static org.junit.Assert.assertEquals;
 
 import java.io.File;
 import java.net.InetSocketAddress;
+import java.nio.charset.StandardCharsets;
 import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
 import java.time.Instant;
@@ -32,9 +33,10 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
-import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIServerName;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLPeerUnverifiedException;
 import javax.net.ssl.SSLSocket;
 import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
@@ -42,7 +44,8 @@ import javax.net.ssl.X509TrustManager;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import org.apache.qpid.server.util.ConnectionScopedRuntimeException;
+
+import org.apache.qpid.server.model.port.AmqpPort;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.ClassRule;
@@ -136,40 +139,46 @@ public class SNITest extends UnitTestBase
     @Test
     public void testValidCertChosen() throws Exception
     {
-        performTest(true, "fooinvalid", "foo", _fooValid);
+        performTest(true, "fooinvalid", "foo", _fooValid, false);
     }
 
     @Test
     public void testMatchCertChosenEvenIfInvalid() throws Exception
     {
-        performTest(true, "fooinvalid", "bar", _barInvalid);
+        performTest(true, "fooinvalid", "bar", _barInvalid, false);
     }
 
     @Test
     public void testDefaultCertChose() throws Exception
     {
-        performTest(true, "fooinvalid", null, _fooInvalid);
+        performTest(true, "fooinvalid", null, _fooInvalid, false);
     }
 
     @Test
     public void testMatchingCanBeDisabled() throws Exception
     {
-        performTest(false, "fooinvalid", "foo", _fooInvalid);
+        performTest(false, "fooinvalid", "foo", _fooInvalid, false);
     }
 
-    @Test(expected = ConnectionScopedRuntimeException.class)
+    @Test(expected = SSLPeerUnverifiedException.class)
     public void testInvalidHostname() throws Exception
     {
-        performTest(false, "fooinvalid", "_foo", _fooInvalid);
+        performTest(false, "fooinvalid", "_foo", _fooInvalid, false);
+    }
+
+    @Test
+    public void testBypassInvalidSniHostname() throws Exception
+    {
+        performTest(false, "foovalid", "_foo", _fooValid,true);
     }
 
 
     private void performTest(final boolean useMatching,
                              final String defaultAlias,
                              final String sniHostName,
-                             final KeyCertificatePair expectedCert) throws Exception
+                             final KeyCertificatePair expectedCert, final boolean ignoreInvalidSni) throws Exception
     {
-            doBrokerStartup(useMatching, defaultAlias);
+            doBrokerStartup(useMatching, defaultAlias, ignoreInvalidSni);
             SSLContext context = SSLUtil.tryGetSSLContext();
             context.init(null,
                          new TrustManager[]
@@ -201,7 +210,7 @@ public class SNITest extends UnitTestBase
                 SSLParameters parameters = socket.getSSLParameters();
                 if (sniHostName != null)
                 {
-                    parameters.setServerNames(Collections.singletonList(SSLUtil.createSNIHostName(sniHostName)));
+                    parameters.setServerNames(Collections.singletonList(new TestSNIHostName(sniHostName)));
                 }
                 socket.setSSLParameters(parameters);
                 InetSocketAddress address = new InetSocketAddress("localhost", _boundPort);
@@ -213,7 +222,7 @@ public class SNITest extends UnitTestBase
             }
     }
 
-    private void doBrokerStartup(boolean useMatching, String defaultAlias) throws Exception
+    private void doBrokerStartup(boolean useMatching, String defaultAlias, final boolean ignoreInvalidSni) throws Exception
     {
         final File initialConfiguration = createInitialContext();
         _brokerWork = TestFileUtils.createTestDirectory("qpid-work", true);
@@ -257,6 +266,7 @@ public class SNITest extends UnitTestBase
         portAttr.put(Port.PORT, 0);
         portAttr.put(Port.AUTHENTICATION_PROVIDER, authProvider);
         portAttr.put(Port.KEY_STORE, keyStore);
+        portAttr.put(Port.CONTEXT, Collections.singletonMap(AmqpPort.PORT_IGNORE_INVALID_SNI, String.valueOf(ignoreInvalidSni)));
 
         final Port<?> port = _broker.createChild(Port.class, portAttr);
 
@@ -274,4 +284,12 @@ public class SNITest extends UnitTestBase
         String config = mapper.writeValueAsString(initialConfig);
         return TestFileUtils.createTempFile(this, ".initial-config.json", config);
     }
+
+    private static final class TestSNIHostName extends SNIServerName
+    {
+        public TestSNIHostName(String hostname)
+        {
+            super(0, hostname.getBytes(StandardCharsets.US_ASCII));
+        }
+    }
 }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/virtualhost/connection/ConnectionPrincipalStatisticsRegistryImplTest.java b/broker-core/src/test/java/org/apache/qpid/server/virtualhost/connection/ConnectionPrincipalStatisticsRegistryImplTest.java
index 61ee675..0c61b8e 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/virtualhost/connection/ConnectionPrincipalStatisticsRegistryImplTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/virtualhost/connection/ConnectionPrincipalStatisticsRegistryImplTest.java
@@ -33,6 +33,7 @@ import java.util.Date;
 import javax.security.auth.Subject;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 
 import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
@@ -101,6 +102,7 @@ public class ConnectionPrincipalStatisticsRegistryImplTest extends UnitTestBase
         assertThat(_statisticsRegistry.getConnectionFrequency(_authorizedPrincipal), is(equalTo(0)));
     }
 
+    @Ignore
     @Test
     public void getConnectionFrequencyAfterExpirationOfFrequencyPeriod() throws InterruptedException
     {

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org