Skip to content

Commit 5fbbb81

Browse files
authored
Merge pull request #592 from RUB-NDS/dynamicWorkflow
Dynamic workflow
2 parents 0586c81 + fa07151 commit 5fbbb81

File tree

5 files changed

+276
-5
lines changed

5 files changed

+276
-5
lines changed

TLS-Core/src/main/java/de/rub/nds/tlsattacker/core/workflow/WorkflowTrace.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ public static WorkflowTrace copy(WorkflowTrace orig) {
132132
@XmlElement(type = SendAction.class, name = "Send"),
133133
@XmlElement(type = SendDynamicClientKeyExchangeAction.class, name = "SendDynamicClientKeyExchange"),
134134
@XmlElement(type = SendDynamicServerKeyExchangeAction.class, name = "SendDynamicServerKeyExchange"),
135+
@XmlElement(type = SendDynamicServerCertificateAction.class, name = "SendDynamicCertificate"),
135136
@XmlElement(type = WaitAction.class, name = "Wait"),
136137
@XmlElement(type = SendAsciiAction.class, name = "SendAscii"),
137138
@XmlElement(type = FlushSessionCacheAction.class, name = "FlushSessionCache"),
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/**
2+
* TLS-Attacker - A Modular Penetration Testing Framework for TLS
3+
*
4+
* Copyright 2014-2017 Ruhr University Bochum / Hackmanit GmbH
5+
*
6+
* Licensed under Apache License 2.0
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*/
9+
package de.rub.nds.tlsattacker.core.workflow.action;
10+
11+
import de.rub.nds.modifiablevariable.ModifiableVariable;
12+
import de.rub.nds.tlsattacker.core.constants.AlgorithmResolver;
13+
import de.rub.nds.tlsattacker.core.constants.CipherSuite;
14+
import de.rub.nds.tlsattacker.core.exceptions.WorkflowExecutionException;
15+
import de.rub.nds.tlsattacker.core.protocol.ModifiableVariableHolder;
16+
import de.rub.nds.tlsattacker.core.protocol.message.CertificateMessage;
17+
import de.rub.nds.tlsattacker.core.protocol.message.ProtocolMessage;
18+
import de.rub.nds.tlsattacker.core.protocol.message.ServerKeyExchangeMessage;
19+
import de.rub.nds.tlsattacker.core.record.AbstractRecord;
20+
import de.rub.nds.tlsattacker.core.state.State;
21+
import de.rub.nds.tlsattacker.core.state.TlsContext;
22+
import de.rub.nds.tlsattacker.core.workflow.action.executor.MessageActionResult;
23+
import de.rub.nds.tlsattacker.core.workflow.factory.WorkflowConfigurationFactory;
24+
import java.io.IOException;
25+
import java.lang.reflect.Field;
26+
import java.util.ArrayList;
27+
import java.util.LinkedList;
28+
import java.util.List;
29+
import java.util.Objects;
30+
import org.apache.logging.log4j.LogManager;
31+
import org.apache.logging.log4j.Logger;
32+
33+
public class SendDynamicServerCertificateAction extends MessageAction implements SendingAction {
34+
35+
private static final Logger LOGGER = LogManager.getLogger();
36+
37+
public SendDynamicServerCertificateAction() {
38+
super();
39+
}
40+
41+
public SendDynamicServerCertificateAction(String connectionAlias) {
42+
super(connectionAlias);
43+
}
44+
45+
@Override
46+
public void execute(State state) throws WorkflowExecutionException {
47+
TlsContext tlsContext = state.getTlsContext(connectionAlias);
48+
49+
if (isExecuted()) {
50+
throw new WorkflowExecutionException("Action already executed!");
51+
}
52+
messages = new LinkedList<>();
53+
WorkflowConfigurationFactory workflowFactory = new WorkflowConfigurationFactory(state.getConfig());
54+
CipherSuite selectedCipherSuite = tlsContext.getSelectedCipherSuite();
55+
if (workflowFactory.shouldServerSendACertificate(selectedCipherSuite)) {
56+
messages.add(new CertificateMessage());
57+
}
58+
String sending = getReadableString(messages);
59+
if (hasDefaultAlias()) {
60+
LOGGER.info("Sending Dynamic Certificate: " + sending);
61+
} else {
62+
LOGGER.info("Sending Dynamic Certificate (" + connectionAlias + "): " + sending);
63+
}
64+
65+
try {
66+
MessageActionResult result = sendMessageHelper.sendMessages(messages, records, tlsContext);
67+
messages = new ArrayList<>(result.getMessageList());
68+
records = new ArrayList<>(result.getRecordList());
69+
setExecuted(true);
70+
} catch (IOException E) {
71+
tlsContext.setReceivedTransportHandlerException(true);
72+
LOGGER.debug(E);
73+
setExecuted(false);
74+
}
75+
}
76+
77+
@Override
78+
public String toString() {
79+
StringBuilder sb;
80+
if (isExecuted()) {
81+
sb = new StringBuilder("Send Dynamic Certificate Action:\n");
82+
} else {
83+
sb = new StringBuilder("Send Dynamic Certificate: (not executed)\n");
84+
}
85+
sb.append("\tMessages:");
86+
if (messages != null) {
87+
for (ProtocolMessage message : messages) {
88+
sb.append(message.toCompactString());
89+
sb.append(", ");
90+
}
91+
sb.append("\n");
92+
} else {
93+
sb.append("null (no messages set)");
94+
}
95+
return sb.toString();
96+
}
97+
98+
@Override
99+
public String toCompactString() {
100+
StringBuilder sb = new StringBuilder(super.toCompactString());
101+
if ((messages != null) && (!messages.isEmpty())) {
102+
sb.append(" (");
103+
for (ProtocolMessage message : messages) {
104+
sb.append(message.toCompactString());
105+
sb.append(",");
106+
}
107+
sb.deleteCharAt(sb.lastIndexOf(",")).append(")");
108+
} else {
109+
sb.append(" (no messages set)");
110+
}
111+
return sb.toString();
112+
}
113+
114+
@Override
115+
public boolean executedAsPlanned() {
116+
return isExecuted();
117+
}
118+
119+
@Override
120+
public void setRecords(List<AbstractRecord> records) {
121+
this.records = records;
122+
}
123+
124+
@Override
125+
public void reset() {
126+
List<ModifiableVariableHolder> holders = new LinkedList<>();
127+
if (messages != null) {
128+
for (ProtocolMessage message : messages) {
129+
holders.addAll(message.getAllModifiableVariableHolders());
130+
}
131+
}
132+
if (getRecords() != null) {
133+
for (AbstractRecord record : getRecords()) {
134+
holders.addAll(record.getAllModifiableVariableHolders());
135+
}
136+
}
137+
for (ModifiableVariableHolder holder : holders) {
138+
List<Field> fields = holder.getAllModifiableVariableFields();
139+
for (Field f : fields) {
140+
f.setAccessible(true);
141+
142+
ModifiableVariable mv = null;
143+
try {
144+
mv = (ModifiableVariable) f.get(holder);
145+
} catch (IllegalArgumentException | IllegalAccessException ex) {
146+
LOGGER.warn("Could not retrieve ModifiableVariables");
147+
LOGGER.debug(ex);
148+
}
149+
if (mv != null) {
150+
if (mv.getModification() != null || mv.isCreateRandomModification()) {
151+
mv.setOriginalValue(null);
152+
} else {
153+
try {
154+
f.set(holder, null);
155+
} catch (IllegalArgumentException | IllegalAccessException ex) {
156+
LOGGER.warn("Could not strip ModifiableVariable without Modification");
157+
}
158+
}
159+
}
160+
}
161+
}
162+
setExecuted(null);
163+
}
164+
165+
@Override
166+
public List<ProtocolMessage> getSendMessages() {
167+
return messages;
168+
}
169+
170+
@Override
171+
public List<AbstractRecord> getSendRecords() {
172+
return records;
173+
}
174+
175+
@Override
176+
public boolean equals(Object obj) {
177+
if (this == obj) {
178+
return true;
179+
}
180+
if (obj == null) {
181+
return false;
182+
}
183+
if (getClass() != obj.getClass()) {
184+
return false;
185+
}
186+
final SendDynamicClientKeyExchangeAction other = (SendDynamicClientKeyExchangeAction) obj;
187+
if (!Objects.equals(this.messages, other.messages)) {
188+
return false;
189+
}
190+
if (!Objects.equals(this.records, other.records)) {
191+
return false;
192+
}
193+
return super.equals(obj);
194+
}
195+
196+
@Override
197+
public int hashCode() {
198+
int hash = super.hashCode();
199+
hash = 67 * hash + Objects.hashCode(this.messages);
200+
hash = 67 * hash + Objects.hashCode(this.records);
201+
202+
return hash;
203+
}
204+
205+
}

TLS-Core/src/main/java/de/rub/nds/tlsattacker/core/workflow/factory/WorkflowConfigurationFactory.java

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,15 @@
4343
import de.rub.nds.tlsattacker.core.workflow.action.PrintLastHandledApplicationDataAction;
4444
import de.rub.nds.tlsattacker.core.workflow.action.PrintSecretsAction;
4545
import de.rub.nds.tlsattacker.core.workflow.action.ReceiveAction;
46+
import de.rub.nds.tlsattacker.core.workflow.action.ReceiveTillAction;
4647
import de.rub.nds.tlsattacker.core.workflow.action.RemBufferedChCiphersAction;
4748
import de.rub.nds.tlsattacker.core.workflow.action.RemBufferedChExtensionsAction;
4849
import de.rub.nds.tlsattacker.core.workflow.action.RenegotiationAction;
4950
import de.rub.nds.tlsattacker.core.workflow.action.ResetConnectionAction;
5051
import de.rub.nds.tlsattacker.core.workflow.action.SendAction;
52+
import de.rub.nds.tlsattacker.core.workflow.action.SendDynamicClientKeyExchangeAction;
53+
import de.rub.nds.tlsattacker.core.workflow.action.SendDynamicServerCertificateAction;
54+
import de.rub.nds.tlsattacker.core.workflow.action.SendDynamicServerKeyExchangeAction;
5155
import de.rub.nds.tlsattacker.core.workflow.action.TlsAction;
5256
import de.rub.nds.tlsattacker.transport.ConnectionEndType;
5357
import java.util.ArrayList;
@@ -64,7 +68,7 @@ public class WorkflowConfigurationFactory {
6468
private static final Logger LOGGER = LogManager.getLogger();
6569

6670
protected final Config config;
67-
RunningModeType mode;
71+
private RunningModeType mode;
6872

6973
public WorkflowConfigurationFactory(Config config) {
7074
this.config = config;
@@ -105,6 +109,8 @@ public WorkflowTrace createWorkflowTrace(WorkflowTraceType type, RunningModeType
105109
return createFalseStartWorkflow();
106110
case RSA_SYNC_PROXY:
107111
return createSyncProxyWorkflow();
112+
case DYNAMIC_HANDSHAKE:
113+
return createDynamicHandshakeWorkflow();
108114
}
109115
throw new ConfigurationException("Unknown WorkflowTraceType " + type.name());
110116
}
@@ -194,8 +200,7 @@ public WorkflowTrace createHelloWorkflow(AliasedConnection connection) {
194200
messages.add(new FinishedMessage(config));
195201
} else {
196202
CipherSuite selectedCipherSuite = config.getDefaultSelectedCipherSuite();
197-
if (!selectedCipherSuite.isSrpSha() && !selectedCipherSuite.isPskOrDhPsk() && !selectedCipherSuite.isAnon()
198-
&& !selectedCipherSuite.isPWD()) {
203+
if (shouldServerSendACertificate(selectedCipherSuite)) {
199204
if (connection.getLocalConnectionEndType() == ConnectionEndType.CLIENT) {
200205
messages.add(new CertificateMessage());
201206
} else {
@@ -216,6 +221,11 @@ public WorkflowTrace createHelloWorkflow(AliasedConnection connection) {
216221
return workflowTrace;
217222
}
218223

224+
public boolean shouldServerSendACertificate(CipherSuite suite) {
225+
return !suite.isSrpSha() && !suite.isPskOrDhPsk() && !suite.isAnon() && !suite.isPWD();
226+
227+
}
228+
219229
/**
220230
* Create a handshake workflow for the default connection end defined in
221231
* config.
@@ -826,4 +836,59 @@ public WorkflowTrace addStartTlsActions(AliasedConnection connection, StarttlsTy
826836
}
827837
return workflowTrace;
828838
}
839+
840+
private WorkflowTrace createDynamicHandshakeWorkflow() {
841+
AliasedConnection connection = getConnection();
842+
WorkflowTrace trace = new WorkflowTrace();
843+
if (config.getStarttlsType() != StarttlsType.NONE) {
844+
addStartTlsActions(connection, config.getStarttlsType(), trace);
845+
}
846+
trace.addTlsAction(MessageActionFactory.createAction(connection, ConnectionEndType.CLIENT,
847+
new ClientHelloMessage(config)));
848+
if (connection.getLocalConnectionEndType() == ConnectionEndType.CLIENT) {
849+
if (config.getHighestProtocolVersion().isTLS13()) {
850+
trace.addTlsAction(new ReceiveTillAction(new FinishedMessage()));
851+
} else {
852+
trace.addTlsAction(new ReceiveTillAction(new ServerHelloDoneMessage()));
853+
}
854+
trace.addTlsAction(new SendDynamicClientKeyExchangeAction());
855+
trace.addTlsAction(new SendAction(new ChangeCipherSpecMessage(config), new FinishedMessage(config)));
856+
trace.addTlsAction(new ReceiveAction(new ChangeCipherSpecMessage(config), new FinishedMessage(config)));
857+
858+
} else {
859+
List<ProtocolMessage> messages = new LinkedList<>();
860+
messages.add(new ServerHelloMessage(config));
861+
862+
if (config.getHighestProtocolVersion().isTLS13()) {
863+
if (config.getTls13BackwardsCompatibilityMode() == Boolean.TRUE) {
864+
messages.add(new ChangeCipherSpecMessage());
865+
}
866+
messages.add(new EncryptedExtensionsMessage(config));
867+
if (config.isClientAuthentication()) {
868+
CertificateRequestMessage certRequest = new CertificateRequestMessage(config);
869+
messages.add(certRequest);
870+
}
871+
messages.add(new CertificateMessage(config));
872+
messages.add(new CertificateVerifyMessage(config));
873+
messages.add(new FinishedMessage(config));
874+
trace.addTlsAction(MessageActionFactory.createAction(connection, ConnectionEndType.SERVER, messages));
875+
876+
} else {
877+
trace.addTlsAction(MessageActionFactory.createAction(connection, ConnectionEndType.SERVER, messages));
878+
trace.addTlsAction(new SendDynamicServerCertificateAction());
879+
trace.addTlsAction(new SendDynamicServerKeyExchangeAction());
880+
messages = new LinkedList<>();
881+
882+
if (config.isClientAuthentication()) {
883+
CertificateRequestMessage certRequest = new CertificateRequestMessage(config);
884+
messages.add(certRequest);
885+
}
886+
messages.add(new ServerHelloDoneMessage(config));
887+
trace.addTlsAction(MessageActionFactory.createAction(connection, ConnectionEndType.SERVER, messages));
888+
trace.addTlsAction(new ReceiveTillAction(new FinishedMessage()));
889+
trace.addTlsAction(new SendAction(new ChangeCipherSpecMessage(config), new FinishedMessage(config)));
890+
}
891+
}
892+
return trace;
893+
}
829894
}

TLS-Core/src/main/java/de/rub/nds/tlsattacker/core/workflow/factory/WorkflowTraceType.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
public enum WorkflowTraceType {
1212
FULL,
1313
HANDSHAKE,
14+
DYNAMIC_HANDSHAKE,
1415
HELLO,
1516
SHORT_HELLO,
1617
RESUMPTION,

TLS-Server/src/main/java/de/rub/nds/tlsattacker/server/config/ServerCommandConfig.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,8 @@ public ServerCommandConfig(GeneralDelegate delegate) {
115115
public Config createConfig() {
116116
Config config = super.createConfig();
117117

118-
// Run FULL trace if no workflow trace (type) is set explicitly
119118
if (config.getWorkflowTraceType() == null) {
120-
config.setWorkflowTraceType(WorkflowTraceType.FULL);
119+
config.setWorkflowTraceType(WorkflowTraceType.HANDSHAKE);
121120
}
122121
return config;
123122
}

0 commit comments

Comments
 (0)