Skip to content

Commit

Permalink
Deny HTTP/3 connection creation for clients missing cert when needCli…
Browse files Browse the repository at this point in the history
…entAuth is true (#12014)

#11996 deny connection creation for clients missing needed cert

Signed-off-by: Ludovic Orban <lorban@bitronix.be>
  • Loading branch information
lorban authored Jul 10, 2024
1 parent 8f5207e commit 17c8a76
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 3 deletions.
21 changes: 21 additions & 0 deletions jetty-core/jetty-http3/jetty-http3-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
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;
Expand Down Expand Up @@ -640,4 +641,24 @@ public void onResponse(Stream.Client stream, HeadersFrame frame)

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));
}
}
2 changes: 1 addition & 1 deletion jetty-core/jetty-quic/jetty-quic-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ protected ProtocolSession createProtocolSession()
return new ClientProtocolSession(this);
}

@Override
protected boolean validateNewlyEstablishedConnection()
{
return true;
}

@Override
public Connection newConnection(QuicStreamEndPoint endPoint)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,9 @@ public Runnable process(SocketAddress remoteAddress, ByteBuffer cipherBufferIn)
ProtocolSession protocol = protocolSession;
if (protocol == null)
{
if (!validateNewlyEstablishedConnection())
return null;

protocolSession = protocol = createProtocolSession();
addManaged(protocol);
}
Expand All @@ -343,6 +346,11 @@ protected Runnable pollTask()

protected abstract ProtocolSession createProtocolSession();

/**
* @return true if the connection is valid, false otherwise.
*/
protected abstract boolean validateNewlyEstablishedConnection();

List<Long> getWritableStreamIds()
{
return quicheConnection.writableStreamIds();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ public static Path[] exportKeyPair(KeyStore keyStore, String alias, char[] keyPa
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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ public Connector getQuicServerConnector()
return connector;
}

ServerQuicConfiguration getQuicConfiguration()
{
return quicConfiguration;
}

@Override
public void onOpen()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
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;
Expand All @@ -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;
Expand All @@ -67,6 +67,18 @@ protected ProtocolSession createProtocolSession()
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)
{
Expand Down

0 comments on commit 17c8a76

Please sign in to comment.