Skip to content

Commit a89b7bc

Browse files
author
Patrick Weixler
committed
Added support for sending and receiving of TLS1.3 KeyUpdate messages
1 parent 28d6652 commit a89b7bc

File tree

14 files changed

+454
-0
lines changed

14 files changed

+454
-0
lines changed

TLS-Core/src/main/java/de/rub/nds/tlsattacker/core/constants/HandshakeByteLength.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,11 @@ public class HandshakeByteLength {
255255
*/
256256
public static final int CERTIFICATE_STATUS_RESPONSE_LENGTH = 3;
257257

258+
/**
259+
* KeyUpdate Message Length
260+
*/
261+
public static final int KEY_UPDATE_LENGTH = 1;
262+
258263
private HandshakeByteLength() {
259264
}
260265
}

TLS-Core/src/main/java/de/rub/nds/tlsattacker/core/constants/HandshakeMessageType.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public enum HandshakeMessageType {
3838
CERTIFICATE_VERIFY((byte) 15),
3939
CLIENT_KEY_EXCHANGE((byte) 16),
4040
FINISHED((byte) 20),
41+
KEY_UPDATE((byte) 24),
4142
CERTIFICATE_STATUS((byte) 22),
4243
SUPPLEMENTAL_DATA((byte) 23),
4344
MESSAGE_HASH((byte) 254);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* TLS-Attacker - A Modular Penetration Testing Framework for TLS
3+
*
4+
* Copyright 2014-2020 Ruhr University Bochum, Paderborn University,
5+
* and Hackmanit GmbH
6+
*
7+
* Licensed under Apache License 2.0
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*/
10+
package de.rub.nds.tlsattacker.core.constants;
11+
12+
import de.rub.nds.modifiablevariable.HoldsModifiableVariable;
13+
14+
public enum KeyUpdateRequest {
15+
16+
UPDATE_NOT_REQUESTED((byte) 0),
17+
UPDATE_REQUESTED((byte) 1);
18+
19+
@HoldsModifiableVariable
20+
private byte request_update;
21+
22+
private KeyUpdateRequest(byte request_update) {
23+
this.request_update = request_update;
24+
}
25+
26+
public byte getValue() {
27+
return request_update;
28+
}
29+
30+
}

TLS-Core/src/main/java/de/rub/nds/tlsattacker/core/crypto/HKDFunction.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ public class HKDFunction {
6161

6262
public static final String RESUMPTION = "resumption";
6363

64+
public static final String TRAFFICUPD = "traffic upd";
65+
66+
6467
private HKDFunction() {
6568
}
6669

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
/**
2+
* TLS-Attacker - A Modular Penetration Testing Framework for TLS
3+
*
4+
* Copyright 2014-2020 Ruhr University Bochum, Paderborn University,
5+
* and Hackmanit GmbH
6+
*
7+
* Licensed under Apache License 2.0
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*/
10+
package de.rub.nds.tlsattacker.core.protocol.handler;
11+
12+
import de.rub.nds.modifiablevariable.util.ArrayConverter;
13+
import de.rub.nds.tlsattacker.core.constants.AlgorithmResolver;
14+
import de.rub.nds.tlsattacker.core.constants.HKDFAlgorithm;
15+
import de.rub.nds.tlsattacker.core.constants.KeyUpdateRequest;
16+
import de.rub.nds.tlsattacker.core.constants.Tls13KeySetType;
17+
import de.rub.nds.tlsattacker.core.crypto.HKDFunction;
18+
import de.rub.nds.tlsattacker.core.exceptions.AdjustmentException;
19+
import de.rub.nds.tlsattacker.core.exceptions.CryptoException;
20+
import de.rub.nds.tlsattacker.core.protocol.message.KeyUpdateMessage;
21+
import de.rub.nds.tlsattacker.core.protocol.parser.KeyUpdateParser;
22+
import de.rub.nds.tlsattacker.core.protocol.parser.ProtocolMessageParser;
23+
import de.rub.nds.tlsattacker.core.protocol.preparator.KeyUpdatePreparator;
24+
import de.rub.nds.tlsattacker.core.protocol.preparator.ProtocolMessagePreparator;
25+
import de.rub.nds.tlsattacker.core.protocol.serializer.KeyUpdateSerializer;
26+
import de.rub.nds.tlsattacker.core.protocol.serializer.ProtocolMessageSerializer;
27+
import de.rub.nds.tlsattacker.core.record.cipher.RecordCipher;
28+
import de.rub.nds.tlsattacker.core.record.cipher.RecordCipherFactory;
29+
import de.rub.nds.tlsattacker.core.record.cipher.cryptohelper.KeySet;
30+
import de.rub.nds.tlsattacker.core.record.cipher.cryptohelper.KeySetGenerator;
31+
import de.rub.nds.tlsattacker.core.state.TlsContext;
32+
import de.rub.nds.tlsattacker.transport.ConnectionEndType;
33+
34+
import java.security.NoSuchAlgorithmException;
35+
36+
import javax.crypto.Mac;
37+
import org.apache.logging.log4j.LogManager;
38+
import org.apache.logging.log4j.Logger;
39+
40+
public class KeyUpdateHandler extends HandshakeMessageHandler<KeyUpdateMessage> {
41+
42+
private static final Logger LOGGER = LogManager.getLogger();
43+
44+
public KeyUpdateHandler(TlsContext tlsContext) {
45+
super(tlsContext);
46+
}
47+
48+
@Override
49+
public void adjustTLSContext(KeyUpdateMessage message) {
50+
51+
}
52+
53+
@Override
54+
public void adjustTlsContextAfterSerialize(KeyUpdateMessage message) {
55+
56+
if (message.getRequestUpdate() == KeyUpdateRequest.UPDATE_REQUESTED) {
57+
adjustApplicationTrafficSecrets();
58+
}
59+
setRecordCipher(Tls13KeySetType.APPLICATION_TRAFFIC_SECRETS);
60+
61+
}
62+
63+
@Override
64+
public ProtocolMessageParser getParser(byte[] message, int pointer) {
65+
66+
return new KeyUpdateParser(pointer, message, tlsContext.getChooser().getSelectedProtocolVersion(),
67+
tlsContext.getConfig());
68+
69+
}
70+
71+
@Override
72+
public ProtocolMessagePreparator getPreparator(KeyUpdateMessage message) {
73+
if (tlsContext.getChooser().getTalkingConnectionEnd() != tlsContext.getChooser().getConnectionEndType()) {
74+
if (message.getRequestUpdate() == KeyUpdateRequest.UPDATE_REQUESTED) {
75+
adjustApplicationTrafficSecrets();
76+
}
77+
setRecordCipher(Tls13KeySetType.APPLICATION_TRAFFIC_SECRETS);
78+
}
79+
return new KeyUpdatePreparator(tlsContext.getChooser(), message);
80+
}
81+
82+
@Override
83+
public ProtocolMessageSerializer getSerializer(KeyUpdateMessage message) {
84+
return new KeyUpdateSerializer(message, tlsContext.getChooser().getSelectedProtocolVersion());
85+
}
86+
87+
private void adjustApplicationTrafficSecrets() {
88+
HKDFAlgorithm hkdfAlgortihm = AlgorithmResolver.getHKDFAlgorithm(tlsContext.getChooser()
89+
.getSelectedCipherSuite());
90+
91+
try {
92+
93+
Mac mac = Mac.getInstance(hkdfAlgortihm.getMacAlgorithm().getJavaName());
94+
byte[] clientApplicationTrafficSecret = HKDFunction.expandLabel(hkdfAlgortihm,
95+
tlsContext.getClientApplicationTrafficSecret(), HKDFunction.TRAFFICUPD, new byte[0],
96+
mac.getMacLength());
97+
98+
tlsContext.setClientApplicationTrafficSecret(clientApplicationTrafficSecret);
99+
LOGGER.debug("Set clientApplicationTrafficSecret in Context to "
100+
+ ArrayConverter.bytesToHexString(clientApplicationTrafficSecret));
101+
102+
byte[] serverApplicationTrafficSecret = HKDFunction.expandLabel(hkdfAlgortihm,
103+
tlsContext.getServerApplicationTrafficSecret(), HKDFunction.TRAFFICUPD, new byte[0],
104+
mac.getMacLength());
105+
106+
tlsContext.setServerApplicationTrafficSecret(serverApplicationTrafficSecret);
107+
LOGGER.debug("Set serverApplicationTrafficSecret in Context to "
108+
+ ArrayConverter.bytesToHexString(serverApplicationTrafficSecret));
109+
110+
} catch (NoSuchAlgorithmException | CryptoException ex) {
111+
throw new AdjustmentException(ex);
112+
}
113+
}
114+
115+
private KeySet getKeySet(TlsContext context, Tls13KeySetType keySetType) {
116+
try {
117+
LOGGER.debug("Generating new KeySet");
118+
KeySet keySet = KeySetGenerator.generateKeySet(context, context.getChooser().getSelectedProtocolVersion(),
119+
keySetType);
120+
121+
return keySet;
122+
} catch (NoSuchAlgorithmException | CryptoException ex) {
123+
throw new UnsupportedOperationException("The specified Algorithm is not supported", ex);
124+
}
125+
}
126+
127+
private void setRecordCipher(Tls13KeySetType keySetType) {
128+
try {
129+
int AEAD_IV_LENGTH = 12;
130+
HKDFAlgorithm hkdfAlgortihm = AlgorithmResolver.getHKDFAlgorithm(tlsContext.getChooser()
131+
.getSelectedCipherSuite());
132+
133+
tlsContext.setActiveClientKeySetType(keySetType);
134+
LOGGER.debug("Setting cipher for client to use " + keySetType);
135+
KeySet keySet = getKeySet(tlsContext, tlsContext.getActiveClientKeySetType());
136+
137+
if (tlsContext.getChooser().getTalkingConnectionEnd() == ConnectionEndType.CLIENT
138+
&& tlsContext.getChooser().getConnectionEndType() == ConnectionEndType.CLIENT
139+
|| tlsContext.getChooser().getTalkingConnectionEnd() == ConnectionEndType.SERVER
140+
&& tlsContext.getChooser().getConnectionEndType() == ConnectionEndType.SERVER) {
141+
142+
if (tlsContext.getChooser().getConnectionEndType() == ConnectionEndType.CLIENT) {
143+
keySet.setClientWriteIv(HKDFunction.expandLabel(hkdfAlgortihm,
144+
tlsContext.getClientApplicationTrafficSecret(), HKDFunction.IV, new byte[0], AEAD_IV_LENGTH));
145+
146+
keySet.setClientWriteKey(HKDFunction.expandLabel(hkdfAlgortihm,
147+
tlsContext.getClientApplicationTrafficSecret(), HKDFunction.KEY, new byte[0],
148+
AlgorithmResolver.getCipher(tlsContext.getChooser().getSelectedCipherSuite()).getKeySize()));
149+
} else {
150+
151+
keySet.setServerWriteIv(HKDFunction.expandLabel(hkdfAlgortihm,
152+
tlsContext.getServerApplicationTrafficSecret(), HKDFunction.IV, new byte[0], AEAD_IV_LENGTH));
153+
154+
keySet.setServerWriteKey(HKDFunction.expandLabel(hkdfAlgortihm,
155+
tlsContext.getServerApplicationTrafficSecret(), HKDFunction.KEY, new byte[0],
156+
AlgorithmResolver.getCipher(tlsContext.getChooser().getSelectedCipherSuite()).getKeySize()));
157+
}
158+
159+
} else if (tlsContext.getChooser().getTalkingConnectionEnd() == ConnectionEndType.SERVER
160+
&& tlsContext.getChooser().getConnectionEndType() == ConnectionEndType.CLIENT
161+
|| tlsContext.getChooser().getTalkingConnectionEnd() == ConnectionEndType.CLIENT
162+
&& tlsContext.getChooser().getConnectionEndType() == ConnectionEndType.SERVER) {
163+
164+
if (tlsContext.getChooser().getConnectionEndType() == ConnectionEndType.SERVER) {
165+
166+
keySet.setServerWriteIv(HKDFunction.expandLabel(hkdfAlgortihm,
167+
tlsContext.getServerApplicationTrafficSecret(), HKDFunction.IV, new byte[0], AEAD_IV_LENGTH));
168+
169+
keySet.setServerWriteKey(HKDFunction.expandLabel(hkdfAlgortihm,
170+
tlsContext.getServerApplicationTrafficSecret(), HKDFunction.KEY, new byte[0],
171+
AlgorithmResolver.getCipher(tlsContext.getChooser().getSelectedCipherSuite()).getKeySize()));
172+
173+
} else {
174+
175+
keySet.setClientWriteIv(HKDFunction.expandLabel(hkdfAlgortihm,
176+
tlsContext.getClientApplicationTrafficSecret(), HKDFunction.IV, new byte[0], AEAD_IV_LENGTH));
177+
178+
keySet.setClientWriteKey(HKDFunction.expandLabel(hkdfAlgortihm,
179+
tlsContext.getClientApplicationTrafficSecret(), HKDFunction.KEY, new byte[0],
180+
AlgorithmResolver.getCipher(tlsContext.getChooser().getSelectedCipherSuite()).getKeySize()));
181+
}
182+
183+
}
184+
185+
RecordCipher recordCipherClient = RecordCipherFactory.getRecordCipher(tlsContext, keySet, tlsContext
186+
.getChooser().getSelectedCipherSuite());
187+
tlsContext.getRecordLayer().setRecordCipher(recordCipherClient);
188+
189+
if (tlsContext.getChooser().getTalkingConnectionEnd() == ConnectionEndType.CLIENT
190+
&& tlsContext.getChooser().getConnectionEndType() == ConnectionEndType.CLIENT
191+
|| tlsContext.getChooser().getTalkingConnectionEnd() == ConnectionEndType.SERVER
192+
&& tlsContext.getChooser().getConnectionEndType() == ConnectionEndType.SERVER) {
193+
194+
tlsContext.setWriteSequenceNumber(0);
195+
tlsContext.getRecordLayer().updateEncryptionCipher();
196+
} else if (tlsContext.getChooser().getTalkingConnectionEnd() == ConnectionEndType.SERVER
197+
&& tlsContext.getChooser().getConnectionEndType() == ConnectionEndType.CLIENT
198+
|| tlsContext.getChooser().getTalkingConnectionEnd() == ConnectionEndType.CLIENT
199+
&& tlsContext.getChooser().getConnectionEndType() == ConnectionEndType.SERVER) {
200+
201+
tlsContext.setReadSequenceNumber(0);
202+
tlsContext.getRecordLayer().updateDecryptionCipher();
203+
}
204+
205+
} catch (CryptoException ex) {
206+
throw new AdjustmentException(ex);
207+
}
208+
209+
}
210+
}

TLS-Core/src/main/java/de/rub/nds/tlsattacker/core/protocol/handler/factory/HandlerFactory.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ public static HandshakeMessageHandler getHandshakeHandler(TlsContext context, Ha
164164
return new HelloVerifyRequestHandler(context);
165165
case NEW_SESSION_TICKET:
166166
return new NewSessionTicketHandler(context);
167+
case KEY_UPDATE:
168+
return new KeyUpdateHandler(context);
167169
case SERVER_HELLO:
168170
return new ServerHelloHandler(context);
169171
case SERVER_HELLO_DONE:
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* TLS-Attacker - A Modular Penetration Testing Framework for TLS
3+
*
4+
* Copyright 2014-2020 Ruhr University Bochum, Paderborn University,
5+
* and Hackmanit GmbH
6+
*
7+
* Licensed under Apache License 2.0
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*/
10+
package de.rub.nds.tlsattacker.core.protocol.message;
11+
12+
import de.rub.nds.modifiablevariable.HoldsModifiableVariable;
13+
import de.rub.nds.tlsattacker.core.config.Config;
14+
import de.rub.nds.tlsattacker.core.constants.HandshakeMessageType;
15+
import de.rub.nds.tlsattacker.core.constants.KeyUpdateRequest;
16+
import de.rub.nds.tlsattacker.core.protocol.handler.ProtocolMessageHandler;
17+
import de.rub.nds.tlsattacker.core.state.TlsContext;
18+
import de.rub.nds.tlsattacker.core.protocol.handler.KeyUpdateHandler;
19+
20+
import org.apache.logging.log4j.LogManager;
21+
import org.apache.logging.log4j.Logger;
22+
23+
public class KeyUpdateMessage extends HandshakeMessage {
24+
25+
private static final Logger LOGGER = LogManager.getLogger();
26+
27+
@HoldsModifiableVariable
28+
private KeyUpdateRequest request_update;
29+
30+
@Override
31+
public ProtocolMessageHandler getHandler(TlsContext context) {
32+
return new KeyUpdateHandler(context);
33+
}
34+
35+
public KeyUpdateMessage() {
36+
super(HandshakeMessageType.KEY_UPDATE);
37+
this.request_update = KeyUpdateRequest.UPDATE_REQUESTED;
38+
}
39+
40+
public KeyUpdateMessage(Config tlsConfig) {
41+
super(tlsConfig, HandshakeMessageType.KEY_UPDATE);
42+
this.request_update = KeyUpdateRequest.UPDATE_REQUESTED;
43+
}
44+
45+
public KeyUpdateMessage(HandshakeMessageType handshakeMessageType, KeyUpdateRequest request_update) {
46+
super(handshakeMessageType);
47+
this.request_update = request_update;
48+
}
49+
50+
public void setRequestUpdate(int keyupdaterequest) {
51+
if (keyupdaterequest == 1) {
52+
request_update = KeyUpdateRequest.UPDATE_REQUESTED;
53+
} else
54+
request_update = KeyUpdateRequest.UPDATE_NOT_REQUESTED;
55+
}
56+
57+
public void setRequestUpdate(KeyUpdateRequest keyupdaterequest) {
58+
request_update = KeyUpdateRequest.UPDATE_REQUESTED;
59+
}
60+
61+
public KeyUpdateRequest getRequestUpdate() {
62+
return this.request_update;
63+
}
64+
65+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* TLS-Attacker - A Modular Penetration Testing Framework for TLS
3+
*
4+
* Copyright 2014-2020 Ruhr University Bochum, Paderborn University,
5+
* and Hackmanit GmbH
6+
*
7+
* Licensed under Apache License 2.0
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*/
10+
package de.rub.nds.tlsattacker.core.protocol.parser;
11+
12+
import org.apache.logging.log4j.LogManager;
13+
import org.apache.logging.log4j.Logger;
14+
15+
import de.rub.nds.modifiablevariable.util.ArrayConverter;
16+
import de.rub.nds.tlsattacker.core.config.Config;
17+
import de.rub.nds.tlsattacker.core.constants.HandshakeByteLength;
18+
import de.rub.nds.tlsattacker.core.constants.HandshakeMessageType;
19+
import de.rub.nds.tlsattacker.core.constants.KeyUpdateRequest;
20+
import de.rub.nds.tlsattacker.core.constants.ProtocolVersion;
21+
import de.rub.nds.tlsattacker.core.protocol.message.KeyUpdateMessage;
22+
23+
public class KeyUpdateParser extends HandshakeMessageParser<KeyUpdateMessage> {
24+
private static final Logger LOGGER = LogManager.getLogger();
25+
26+
public KeyUpdateParser(int pointer, byte[] array, ProtocolVersion version, Config config) {
27+
super(pointer, array, HandshakeMessageType.KEY_UPDATE, version, config);
28+
}
29+
30+
@Override
31+
protected void parseHandshakeMessageContent(KeyUpdateMessage msg) {
32+
LOGGER.debug("Parsing KeyUpdateMessage");
33+
parseUpdateRequest(msg);
34+
}
35+
36+
@Override
37+
protected KeyUpdateMessage createHandshakeMessage() {
38+
return new KeyUpdateMessage();
39+
}
40+
41+
private void parseUpdateRequest(KeyUpdateMessage msg) {
42+
msg.setRequestUpdate(parseIntField(HandshakeByteLength.KEY_UPDATE_LENGTH));
43+
LOGGER.debug("KeyUpdateValue: " + msg.getRequestUpdate().getValue());
44+
45+
}
46+
47+
}

0 commit comments

Comments
 (0)