10
10
11
11
import java .util .ArrayList ;
12
12
import java .util .Arrays ;
13
+ import java .util .Collections ;
13
14
import java .util .LinkedList ;
14
15
import java .util .List ;
15
16
18
19
import javax .crypto .spec .IvParameterSpec ;
19
20
import javax .crypto .spec .SecretKeySpec ;
20
21
22
+ import org .apache .commons .lang3 .ArrayUtils ;
23
+
21
24
import de .rub .nds .modifiablevariable .util .ArrayConverter ;
22
25
import de .rub .nds .tlsattacker .core .config .Config ;
23
26
import de .rub .nds .tlsattacker .core .constants .CipherSuite ;
38
41
import de .rub .nds .tlsscanner .report .result .ProbeResult ;
39
42
import de .rub .nds .tlsscanner .report .result .SessionTicketZeroKeyResult ;
40
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
+ */
41
59
public class SessionTicketZeroKeyProbe extends TlsProbe {
42
60
61
+ /**
62
+ * Magic Bytes the plaintext state in GnuTls starts with
63
+ */
43
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
+ */
44
69
public static final int IV_OFFSET = 16 ;
70
+
71
+ /**
72
+ * Length of the IV according to the ticket struct in rfc5077
73
+ */
45
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
+ */
46
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
+ */
47
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
+ */
48
91
public static final int SESSION_STATE_OFFSET = 34 ;
92
+
49
93
private List <CipherSuite > supportedSuites ;
50
94
51
95
public SessionTicketZeroKeyProbe (ScannerConfig scannerConfig , ParallelExecutor parallelExecutor ) {
@@ -79,13 +123,11 @@ public ProbeResult executeTest() {
79
123
executeState (state );
80
124
} catch (Exception E ) {
81
125
LOGGER .error ("Could not scan for " + getProbeName (), E );
82
- return new SessionTicketZeroKeyResult (TestResult .ERROR_DURING_TEST , TestResult .ERROR_DURING_TEST ,
83
- TestResult .ERROR_DURING_TEST );
126
+ return new SessionTicketZeroKeyResult (TestResult .ERROR_DURING_TEST , TestResult .ERROR_DURING_TEST );
84
127
}
85
128
86
129
if (!WorkflowTraceUtil .didReceiveMessage (HandshakeMessageType .NEW_SESSION_TICKET , state .getWorkflowTrace ())) {
87
- return new SessionTicketZeroKeyResult (TestResult .UNSUPPORTED , TestResult .UNSUPPORTED ,
88
- TestResult .UNSUPPORTED );
130
+ return new SessionTicketZeroKeyResult (TestResult .UNSUPPORTED , TestResult .UNSUPPORTED );
89
131
}
90
132
91
133
byte [] ticket = null ;
@@ -96,8 +138,7 @@ public ProbeResult executeTest() {
96
138
}
97
139
}
98
140
99
- byte [] key = ArrayConverter
100
- .hexStringToByteArray ("0000000000000000000000000000000000000000000000000000000000000000" );
141
+ byte [] key = new byte [32 ];
101
142
byte [] iv , encryptedSessionState ;
102
143
byte [] decryptedSessionState = null ;
103
144
@@ -114,9 +155,8 @@ public ProbeResult executeTest() {
114
155
decryptedSessionState = cipher .doFinal (encryptedSessionState );
115
156
LOGGER .debug ("decryptedSsessionState" + ArrayConverter .bytesToHexString (decryptedSessionState ));
116
157
} catch (Exception e ) {
117
- return new SessionTicketZeroKeyResult (TestResult .FALSE , TestResult .FALSE , TestResult . FALSE );
158
+ return new SessionTicketZeroKeyResult (TestResult .FALSE , TestResult .FALSE );
118
159
}
119
- TestResult hasCorrectPadding = TestResult .TRUE ;
120
160
TestResult hasDecryptableMasterSecret ;
121
161
TestResult hasGnuTlsMagicBytes ;
122
162
@@ -125,14 +165,15 @@ public ProbeResult executeTest() {
125
165
} else {
126
166
hasDecryptableMasterSecret = TestResult .FALSE ;
127
167
}
168
+
128
169
if (checkForGnuTlsMagicBytes (decryptedSessionState )) {
129
170
hasGnuTlsMagicBytes = TestResult .TRUE ;
130
171
131
172
} else {
132
173
hasGnuTlsMagicBytes = TestResult .FALSE ;
133
174
}
134
175
135
- return new SessionTicketZeroKeyResult (hasCorrectPadding , hasDecryptableMasterSecret , hasGnuTlsMagicBytes );
176
+ return new SessionTicketZeroKeyResult (hasDecryptableMasterSecret , hasGnuTlsMagicBytes );
136
177
}
137
178
138
179
@ Override
@@ -141,20 +182,12 @@ public boolean canBeExecuted(SiteReport report) {
141
182
}
142
183
143
184
private boolean checkForMasterSecret (byte [] decState , TlsContext context ) {
144
- boolean found = false ;
145
- byte [] ms = context .getMasterSecret ();
146
- for (int i = 0 ; i < decState .length - ms .length ; i ++) {
147
- found = true ;
148
- for (int j = 0 ; j < ms .length ; j ++) {
149
- if (decState [i + j ] != ms [j ]) {
150
- found = false ;
151
- break ;
152
- }
153
- }
154
- if (found )
155
- return true ;
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 ;
156
189
}
157
- return false ;
190
+ return true ;
158
191
}
159
192
160
193
private boolean checkForGnuTlsMagicBytes (byte [] decState ) {
@@ -170,13 +203,12 @@ private boolean checkForGnuTlsMagicBytes(byte[] decState) {
170
203
171
204
@ Override
172
205
public ProbeResult getCouldNotExecuteResult () {
173
- return new SessionTicketZeroKeyResult (TestResult .COULD_NOT_TEST , TestResult .COULD_NOT_TEST ,
174
- TestResult .COULD_NOT_TEST );
206
+ return new SessionTicketZeroKeyResult (TestResult .COULD_NOT_TEST , TestResult .COULD_NOT_TEST );
175
207
}
176
208
177
209
@ Override
178
210
public void adjustConfig (SiteReport report ) {
179
- supportedSuites = new ArrayList <>(report .getCipherSuites ());
211
+ supportedSuites = new ArrayList <>(report .getCipherSuites ());
180
212
}
181
213
182
- }
214
+ }
0 commit comments