Skip to content

Commit 3efb7da

Browse files
committed
merged public master into master
2 parents 695603e + 519f53f commit 3efb7da

File tree

2 files changed

+248
-0
lines changed

2 files changed

+248
-0
lines changed
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
/**
2+
* TLS-Scanner - A TLS configuration and analysis tool based on TLS-Attacker.
3+
*
4+
* Copyright 2017-2019 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.tlsscanner.probe;
10+
11+
import java.util.ArrayList;
12+
import java.util.Arrays;
13+
import java.util.Collections;
14+
import java.util.LinkedList;
15+
import java.util.List;
16+
17+
import javax.crypto.Cipher;
18+
import javax.crypto.SecretKey;
19+
import javax.crypto.spec.IvParameterSpec;
20+
import javax.crypto.spec.SecretKeySpec;
21+
22+
import org.apache.commons.lang3.ArrayUtils;
23+
24+
import de.rub.nds.modifiablevariable.util.ArrayConverter;
25+
import de.rub.nds.tlsattacker.core.config.Config;
26+
import de.rub.nds.tlsattacker.core.constants.CipherSuite;
27+
import de.rub.nds.tlsattacker.core.constants.HandshakeMessageType;
28+
import de.rub.nds.tlsattacker.core.constants.NamedGroup;
29+
import de.rub.nds.tlsattacker.core.constants.ProtocolVersion;
30+
import de.rub.nds.tlsattacker.core.protocol.message.NewSessionTicketMessage;
31+
import de.rub.nds.tlsattacker.core.protocol.message.ProtocolMessage;
32+
import de.rub.nds.tlsattacker.core.state.State;
33+
import de.rub.nds.tlsattacker.core.state.TlsContext;
34+
import de.rub.nds.tlsattacker.core.workflow.ParallelExecutor;
35+
import de.rub.nds.tlsattacker.core.workflow.WorkflowTraceUtil;
36+
import de.rub.nds.tlsattacker.core.workflow.factory.WorkflowTraceType;
37+
import de.rub.nds.tlsscanner.config.ScannerConfig;
38+
import de.rub.nds.tlsscanner.constants.ProbeType;
39+
import de.rub.nds.tlsscanner.rating.TestResult;
40+
import de.rub.nds.tlsscanner.report.SiteReport;
41+
import de.rub.nds.tlsscanner.report.result.ProbeResult;
42+
import de.rub.nds.tlsscanner.report.result.SessionTicketZeroKeyResult;
43+
44+
/**
45+
*
46+
* The Probe checks for CVE-2020-13777.
47+
*
48+
* Quote: "GnuTLS 3.6.x before 3.6.14 uses incorrect cryptography for encrypting
49+
* a session ticket (a loss of confidentiality in TLS 1.2, and an authentication
50+
* bypass in TLS 1.3). The earliest affected version is 3.6.4 (2018-09-24)
51+
* because of an error in a 2018-09-18 commit. Until the first key rotation, the
52+
* TLS server always uses wrong data in place of an encryption key derived from
53+
* an application."[1]
54+
*
55+
* Reference [1]: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-13777
56+
* Reference [2]: https://www.gnutls.org/security-new.html
57+
*
58+
*/
59+
public class SessionTicketZeroKeyProbe extends TlsProbe {
60+
61+
/**
62+
* Magic Bytes the plaintext state in GnuTls starts with
63+
*/
64+
public static final byte[] GNU_TLS_MAGIC_BYTES = ArrayConverter.hexStringToByteArray("FAE1C0EA");
65+
66+
/**
67+
* Offset of the IV according to the ticket struct in rfc5077
68+
*/
69+
public static final int IV_OFFSET = 16;
70+
71+
/**
72+
* Length of the IV according to the ticket struct in rfc5077
73+
*/
74+
public static final int IV_LEN = 16;
75+
76+
/**
77+
* Offset of the length field for the in the encrypted state according to
78+
* the ticket struct in rfc5077
79+
*/
80+
public static final int SESSION_STATE_LENFIELD_OFFSET = 32;
81+
82+
/**
83+
* Length of the length field for the in the encrypted state according to
84+
* the ticket struct in rfc5077
85+
*/
86+
public static final int SESSION_STATE_LENFIELD_LEN = 2;
87+
88+
/**
89+
* Offset of the encrypted state according to the ticket struct in rfc5077
90+
*/
91+
public static final int SESSION_STATE_OFFSET = 34;
92+
93+
private List<CipherSuite> supportedSuites;
94+
95+
public SessionTicketZeroKeyProbe(ScannerConfig scannerConfig, ParallelExecutor parallelExecutor) {
96+
super(parallelExecutor, ProbeType.SESSION_TICKET_ZERO_KEY, scannerConfig, 0);
97+
}
98+
99+
public SessionTicketZeroKeyProbe(ParallelExecutor parallelExecutor, ProbeType type, ScannerConfig scannerConfig,
100+
int danger) {
101+
super(parallelExecutor, type, scannerConfig, danger);
102+
}
103+
104+
@Override
105+
public ProbeResult executeTest() {
106+
State state;
107+
try {
108+
Config tlsConfig = getScannerConfig().createConfig();
109+
tlsConfig.setQuickReceive(true);
110+
List<CipherSuite> ciphersuites = new LinkedList<>();
111+
ciphersuites.addAll(supportedSuites);
112+
tlsConfig.setDefaultClientNamedGroups(NamedGroup.getImplemented());
113+
tlsConfig.setWorkflowTraceType(WorkflowTraceType.HANDSHAKE);
114+
tlsConfig.setHighestProtocolVersion(ProtocolVersion.TLS12);
115+
tlsConfig.setDefaultClientSupportedCiphersuites(ciphersuites.get(0));
116+
tlsConfig.setDefaultSelectedCipherSuite(tlsConfig.getDefaultClientSupportedCiphersuites().get(0));
117+
tlsConfig.setAddECPointFormatExtension(true);
118+
tlsConfig.setAddEllipticCurveExtension(true);
119+
tlsConfig.setAddSessionTicketTLSExtension(true);
120+
tlsConfig.setAddServerNameIndicationExtension(true);
121+
tlsConfig.setAddRenegotiationInfoExtension(false);
122+
state = new State(tlsConfig);
123+
executeState(state);
124+
} catch (Exception E) {
125+
LOGGER.error("Could not scan for " + getProbeName(), E);
126+
return new SessionTicketZeroKeyResult(TestResult.ERROR_DURING_TEST, TestResult.ERROR_DURING_TEST);
127+
}
128+
129+
if (!WorkflowTraceUtil.didReceiveMessage(HandshakeMessageType.NEW_SESSION_TICKET, state.getWorkflowTrace())) {
130+
return new SessionTicketZeroKeyResult(TestResult.UNSUPPORTED, TestResult.UNSUPPORTED);
131+
}
132+
133+
byte[] ticket = null;
134+
for (ProtocolMessage msg : WorkflowTraceUtil.getAllReceivedMessages(state.getWorkflowTrace())) {
135+
if (msg instanceof NewSessionTicketMessage) {
136+
NewSessionTicketMessage newSessionTicketMessage = (NewSessionTicketMessage) msg;
137+
ticket = newSessionTicketMessage.getTicket().getIdentity().getValue();
138+
}
139+
}
140+
141+
byte[] key = new byte[32];
142+
byte[] iv, encryptedSessionState;
143+
byte[] decryptedSessionState = null;
144+
145+
try {
146+
iv = Arrays.copyOfRange(ticket, IV_OFFSET, IV_OFFSET + IV_LEN);
147+
byte[] sessionStateLen = Arrays.copyOfRange(ticket, SESSION_STATE_LENFIELD_OFFSET,
148+
SESSION_STATE_LENFIELD_OFFSET + SESSION_STATE_LENFIELD_LEN);
149+
int sessionStateLenInt = ArrayConverter.bytesToInt(sessionStateLen);
150+
encryptedSessionState = Arrays.copyOfRange(ticket, SESSION_STATE_OFFSET, SESSION_STATE_OFFSET
151+
+ sessionStateLenInt);
152+
Cipher cipher = Cipher.getInstance("AES/CBC/NOPADDING");
153+
SecretKey aesKey = new SecretKeySpec(key, "AES");
154+
cipher.init(Cipher.DECRYPT_MODE, aesKey, new IvParameterSpec(iv));
155+
decryptedSessionState = cipher.doFinal(encryptedSessionState);
156+
LOGGER.debug("decryptedSsessionState" + ArrayConverter.bytesToHexString(decryptedSessionState));
157+
} catch (Exception e) {
158+
return new SessionTicketZeroKeyResult(TestResult.FALSE, TestResult.FALSE);
159+
}
160+
TestResult hasDecryptableMasterSecret;
161+
TestResult hasGnuTlsMagicBytes;
162+
163+
if (checkForMasterSecret(decryptedSessionState, state.getTlsContext())) {
164+
hasDecryptableMasterSecret = TestResult.TRUE;
165+
} else {
166+
hasDecryptableMasterSecret = TestResult.FALSE;
167+
}
168+
169+
if (checkForGnuTlsMagicBytes(decryptedSessionState)) {
170+
hasGnuTlsMagicBytes = TestResult.TRUE;
171+
172+
} else {
173+
hasGnuTlsMagicBytes = TestResult.FALSE;
174+
}
175+
176+
return new SessionTicketZeroKeyResult(hasDecryptableMasterSecret, hasGnuTlsMagicBytes);
177+
}
178+
179+
@Override
180+
public boolean canBeExecuted(SiteReport report) {
181+
return report.getCipherSuites() != null && (report.getCipherSuites().size() > 0);
182+
}
183+
184+
private boolean checkForMasterSecret(byte[] decState, TlsContext context) {
185+
List<Byte> target = Arrays.asList(ArrayUtils.toObject(context.getMasterSecret()));
186+
List<Byte> source = Arrays.asList(ArrayUtils.toObject(decState));
187+
if (Collections.indexOfSubList(source, target) == -1) {
188+
return false;
189+
}
190+
return true;
191+
}
192+
193+
private boolean checkForGnuTlsMagicBytes(byte[] decState) {
194+
try {
195+
for (int i = 0; i < GNU_TLS_MAGIC_BYTES.length; i++)
196+
if (decState[i] != GNU_TLS_MAGIC_BYTES[i])
197+
return false;
198+
} catch (Exception e) {
199+
return false;
200+
}
201+
return true;
202+
}
203+
204+
@Override
205+
public ProbeResult getCouldNotExecuteResult() {
206+
return new SessionTicketZeroKeyResult(TestResult.COULD_NOT_TEST, TestResult.COULD_NOT_TEST);
207+
}
208+
209+
@Override
210+
public void adjustConfig(SiteReport report) {
211+
supportedSuites = new ArrayList<>(report.getCipherSuites());
212+
}
213+
214+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* TLS-Scanner - A TLS configuration and analysis tool based on TLS-Attacker.
3+
*
4+
* Copyright 2017-2019 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.tlsscanner.report.result;
10+
11+
import de.rub.nds.tlsscanner.rating.TestResult;
12+
import de.rub.nds.tlsscanner.constants.ProbeType;
13+
import de.rub.nds.tlsscanner.report.AnalyzedProperty;
14+
import de.rub.nds.tlsscanner.report.SiteReport;
15+
16+
public class SessionTicketZeroKeyResult extends ProbeResult {
17+
18+
private TestResult hasDecryptableMasterSecret;
19+
private TestResult hasGnuTlsMagicBytes;
20+
21+
public SessionTicketZeroKeyResult(TestResult hasDecryptableMasterSecret, TestResult hasGnuTlsMagicBytes) {
22+
super(ProbeType.SESSION_TICKET_ZERO_KEY);
23+
this.hasDecryptableMasterSecret = hasDecryptableMasterSecret;
24+
this.hasGnuTlsMagicBytes = hasGnuTlsMagicBytes;
25+
26+
}
27+
28+
@Override
29+
protected void mergeData(SiteReport report) {
30+
report.putResult(AnalyzedProperty.VULNERABLE_TO_SESSION_TICKET_ZERO_KEY, this.hasDecryptableMasterSecret);
31+
report.putResult(AnalyzedProperty.HAS_GNU_TLS_MAGIC_BYTES, this.hasGnuTlsMagicBytes);
32+
}
33+
34+
}

0 commit comments

Comments
 (0)