From 5b0c9f23745ccdae35e83155f0d52d3a808fc51e Mon Sep 17 00:00:00 2001 From: TLS-Attacker Contributor Date: Thu, 26 Jun 2025 15:45:54 +0000 Subject: [PATCH] Fix ThreadedServerWorkflowExecutor with DTLS protocols Add validation to prevent ThreadedServerWorkflowExecutor from being used with DTLS protocols. Since Java's DatagramSocket API doesn't support spawning new sockets for each client connection, the threaded executor model is incompatible with UDP-based DTLS. The fix adds a check in WorkflowExecutorFactory to throw an informative error message when THREADED_SERVER executor type is used with DTLS protocols, directing users to use the DTLS executor instead. Fixes #184 --- .../workflow/WorkflowExecutorFactory.java | 9 ++ .../workflow/WorkflowExecutorFactoryTest.java | 108 ++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 TLS-Core/src/test/java/de/rub/nds/tlsattacker/core/workflow/WorkflowExecutorFactoryTest.java diff --git a/TLS-Core/src/main/java/de/rub/nds/tlsattacker/core/workflow/WorkflowExecutorFactory.java b/TLS-Core/src/main/java/de/rub/nds/tlsattacker/core/workflow/WorkflowExecutorFactory.java index c541fd2e7b..6cc75f855d 100644 --- a/TLS-Core/src/main/java/de/rub/nds/tlsattacker/core/workflow/WorkflowExecutorFactory.java +++ b/TLS-Core/src/main/java/de/rub/nds/tlsattacker/core/workflow/WorkflowExecutorFactory.java @@ -18,6 +18,15 @@ public static WorkflowExecutor createWorkflowExecutor(WorkflowExecutorType type, case DEFAULT: return new DefaultWorkflowExecutor(state); case THREADED_SERVER: + if (state.getConfig().getHighestProtocolVersion() != null + && state.getConfig().getHighestProtocolVersion().isDTLS()) { + throw new UnsupportedOperationException( + "ThreadedServerWorkflowExecutor is not supported for DTLS protocols. " + + "For UDP/DTLS, Java's DatagramSocket API does not allow spawning " + + "new sockets for each client connection. Use the default DTLS " + + "executor instead by removing the -executor_type parameter or " + + "setting it to DTLS."); + } return new ThreadedServerWorkflowExecutor(state); case DTLS: return new DTLSWorkflowExecutor(state); diff --git a/TLS-Core/src/test/java/de/rub/nds/tlsattacker/core/workflow/WorkflowExecutorFactoryTest.java b/TLS-Core/src/test/java/de/rub/nds/tlsattacker/core/workflow/WorkflowExecutorFactoryTest.java new file mode 100644 index 0000000000..43e5efc419 --- /dev/null +++ b/TLS-Core/src/test/java/de/rub/nds/tlsattacker/core/workflow/WorkflowExecutorFactoryTest.java @@ -0,0 +1,108 @@ +/* + * TLS-Attacker - A Modular Penetration Testing Framework for TLS + * + * Copyright 2014-2023 Ruhr University Bochum, Paderborn University, Technology Innovation Institute, and Hackmanit GmbH + * + * Licensed under Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0.txt + */ +package de.rub.nds.tlsattacker.core.workflow; + +import static org.junit.jupiter.api.Assertions.*; + +import de.rub.nds.tlsattacker.core.config.Config; +import de.rub.nds.tlsattacker.core.constants.ProtocolVersion; +import de.rub.nds.tlsattacker.core.state.State; +import de.rub.nds.tlsattacker.core.workflow.action.executor.WorkflowExecutorType; +import org.junit.jupiter.api.Test; + +public class WorkflowExecutorFactoryTest { + + @Test + public void testCreateDefaultExecutor() { + Config config = new Config(); + State state = new State(config); + WorkflowExecutor executor = + WorkflowExecutorFactory.createWorkflowExecutor(WorkflowExecutorType.DEFAULT, state); + assertNotNull(executor); + assertTrue(executor instanceof DefaultWorkflowExecutor); + } + + @Test + public void testCreateDtlsExecutor() { + Config config = new Config(); + State state = new State(config); + WorkflowExecutor executor = + WorkflowExecutorFactory.createWorkflowExecutor(WorkflowExecutorType.DTLS, state); + assertNotNull(executor); + assertTrue(executor instanceof DTLSWorkflowExecutor); + } + + @Test + public void testCreateThreadedServerExecutorWithTls() { + Config config = new Config(); + config.setHighestProtocolVersion(ProtocolVersion.TLS12); + State state = new State(config); + WorkflowExecutor executor = + WorkflowExecutorFactory.createWorkflowExecutor( + WorkflowExecutorType.THREADED_SERVER, state); + assertNotNull(executor); + assertTrue(executor instanceof ThreadedServerWorkflowExecutor); + } + + @Test + public void testThreadedServerExecutorWithDtlsThrowsException() { + Config config = new Config(); + config.setHighestProtocolVersion(ProtocolVersion.DTLS12); + State state = new State(config); + + UnsupportedOperationException exception = + assertThrows( + UnsupportedOperationException.class, + () -> + WorkflowExecutorFactory.createWorkflowExecutor( + WorkflowExecutorType.THREADED_SERVER, state)); + + assertTrue( + exception + .getMessage() + .contains("ThreadedServerWorkflowExecutor is not supported for DTLS")); + assertTrue(exception.getMessage().contains("DatagramSocket API")); + } + + @Test + public void testThreadedServerExecutorWithDtls10ThrowsException() { + Config config = new Config(); + config.setHighestProtocolVersion(ProtocolVersion.DTLS10); + State state = new State(config); + + UnsupportedOperationException exception = + assertThrows( + UnsupportedOperationException.class, + () -> + WorkflowExecutorFactory.createWorkflowExecutor( + WorkflowExecutorType.THREADED_SERVER, state)); + + assertTrue( + exception + .getMessage() + .contains("ThreadedServerWorkflowExecutor is not supported for DTLS")); + } + + @Test + public void testThreadedServerExecutorWithNullProtocolVersion() { + Config config = new Config(); + config.setHighestProtocolVersion(null); + // Pass a pre-defined workflow trace to avoid State creating a default one which requires + // protocol version + WorkflowTrace trace = new WorkflowTrace(); + State state = new State(config, trace); + + // Should not throw exception when protocol version is null + WorkflowExecutor executor = + WorkflowExecutorFactory.createWorkflowExecutor( + WorkflowExecutorType.THREADED_SERVER, state); + assertNotNull(executor); + assertTrue(executor instanceof ThreadedServerWorkflowExecutor); + } +}