Deny HTTP/3 connection creation for clients missing cert when needClientAuth is true (#12014)
#11996 deny connection creation for clients missing needed cert Signed-off-by: Ludovic Orban <lorban@bitronix.be>
This commit is contained in:
parent
8f5207e6ca
commit
17c8a76efb
|
@ -66,4 +66,25 @@
|
|||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>enable-foreign</id>
|
||||
<activation>
|
||||
<jdk>[22,)</jdk>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>@{argLine}
|
||||
${jetty.surefire.argLine}
|
||||
--enable-native-access=ALL-UNNAMED</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.eclipse.jetty.http3.frames.SettingsFrame;
|
|||
import org.eclipse.jetty.http3.server.AbstractHTTP3ServerConnectionFactory;
|
||||
import org.eclipse.jetty.http3.server.internal.HTTP3SessionServer;
|
||||
import org.eclipse.jetty.quic.client.ClientQuicSession;
|
||||
import org.eclipse.jetty.quic.common.QuicErrorCode;
|
||||
import org.eclipse.jetty.quic.common.QuicSession;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -640,4 +641,24 @@ public class ClientServerTest extends AbstractClientServerTest
|
|||
|
||||
assertTrue(responseLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingNeededClientCertificateDeniesConnection() throws Exception
|
||||
{
|
||||
start(new Session.Server.Listener() {});
|
||||
connector.getQuicConfiguration().getSslContextFactory().setNeedClientAuth(true);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
newSession(new Session.Client.Listener()
|
||||
{
|
||||
@Override
|
||||
public void onDisconnect(Session session, long error, String reason)
|
||||
{
|
||||
assertEquals(QuicErrorCode.CONNECTION_REFUSED.code(), error);
|
||||
assertEquals("missing_client_certificate_chain", reason);
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
<configuration>
|
||||
<argLine>@{argLine}
|
||||
${jetty.surefire.argLine}
|
||||
--enable-native-access org.eclipse.jetty.quic.quiche.foreign</argLine>
|
||||
--enable-native-access=ALL-UNNAMED</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
|
|
@ -74,6 +74,12 @@ public class ClientQuicSession extends QuicSession
|
|||
return new ClientProtocolSession(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean validateNewlyEstablishedConnection()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection newConnection(QuicStreamEndPoint endPoint)
|
||||
{
|
||||
|
|
|
@ -319,6 +319,9 @@ public abstract class QuicSession extends ContainerLifeCycle
|
|||
ProtocolSession protocol = protocolSession;
|
||||
if (protocol == null)
|
||||
{
|
||||
if (!validateNewlyEstablishedConnection())
|
||||
return null;
|
||||
|
||||
protocolSession = protocol = createProtocolSession();
|
||||
addManaged(protocol);
|
||||
}
|
||||
|
@ -343,6 +346,11 @@ public abstract class QuicSession extends ContainerLifeCycle
|
|||
|
||||
protected abstract ProtocolSession createProtocolSession();
|
||||
|
||||
/**
|
||||
* @return true if the connection is valid, false otherwise.
|
||||
*/
|
||||
protected abstract boolean validateNewlyEstablishedConnection();
|
||||
|
||||
List<Long> getWritableStreamIds()
|
||||
{
|
||||
return quicheConnection.writableStreamIds();
|
||||
|
|
|
@ -80,6 +80,9 @@ public class PemExporter
|
|||
try (OutputStream os = Files.newOutputStream(paths[1]))
|
||||
{
|
||||
Certificate[] certChain = keyStore.getCertificateChain(alias);
|
||||
if (certChain == null)
|
||||
throw new IllegalArgumentException("Alias does not exist in key store: " + alias);
|
||||
|
||||
for (Certificate cert : certChain)
|
||||
writeAsPEM(os, cert);
|
||||
Files.setPosixFilePermissions(paths[1], Set.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE));
|
||||
|
|
|
@ -71,6 +71,11 @@ public class ServerQuicConnection extends QuicConnection
|
|||
return connector;
|
||||
}
|
||||
|
||||
ServerQuicConfiguration getQuicConfiguration()
|
||||
{
|
||||
return quicConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen()
|
||||
{
|
||||
|
|
|
@ -25,7 +25,7 @@ import org.eclipse.jetty.io.Connection;
|
|||
import org.eclipse.jetty.io.CyclicTimeouts;
|
||||
import org.eclipse.jetty.io.RuntimeIOException;
|
||||
import org.eclipse.jetty.quic.common.ProtocolSession;
|
||||
import org.eclipse.jetty.quic.common.QuicConnection;
|
||||
import org.eclipse.jetty.quic.common.QuicErrorCode;
|
||||
import org.eclipse.jetty.quic.common.QuicSession;
|
||||
import org.eclipse.jetty.quic.common.QuicStreamEndPoint;
|
||||
import org.eclipse.jetty.quic.quiche.QuicheConnection;
|
||||
|
@ -46,7 +46,7 @@ public class ServerQuicSession extends QuicSession implements CyclicTimeouts.Exp
|
|||
private final Connector connector;
|
||||
private long expireNanoTime = Long.MAX_VALUE;
|
||||
|
||||
public ServerQuicSession(Executor executor, Scheduler scheduler, ByteBufferPool bufferPool, QuicheConnection quicheConnection, QuicConnection connection, SocketAddress remoteAddress, Connector connector)
|
||||
public ServerQuicSession(Executor executor, Scheduler scheduler, ByteBufferPool bufferPool, QuicheConnection quicheConnection, ServerQuicConnection connection, SocketAddress remoteAddress, Connector connector)
|
||||
{
|
||||
super(executor, scheduler, bufferPool, quicheConnection, connection, remoteAddress);
|
||||
this.connector = connector;
|
||||
|
@ -67,6 +67,18 @@ public class ServerQuicSession extends QuicSession implements CyclicTimeouts.Exp
|
|||
return new ServerProtocolSession(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean validateNewlyEstablishedConnection()
|
||||
{
|
||||
if (getQuicConnection().getQuicConfiguration().getSslContextFactory().getNeedClientAuth() && getPeerCertificates() == null)
|
||||
{
|
||||
outwardClose(QuicErrorCode.CONNECTION_REFUSED.code(), "missing_client_certificate_chain");
|
||||
flush();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection newConnection(QuicStreamEndPoint endPoint)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue