Skip to content

Commit 8f7d8cb

Browse files
committed
Refactor timing attack queries
1 parent 597949d commit 8f7d8cb

File tree

3 files changed

+41
-39
lines changed

3 files changed

+41
-39
lines changed

java/ql/src/experimental/Security/CWE/CWE-208/NonConstantTimeCheckOnSignatureQuery.qll

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
import semmle.code.java.controlflow.Guards
66
import semmle.code.java.dataflow.TaintTracking
7-
import semmle.code.java.dataflow.TaintTracking2
8-
import semmle.code.java.dataflow.DataFlow3
97
import semmle.code.java.dataflow.FlowSources
108

119
/** A method call that produces cryptographic result. */
@@ -51,25 +49,25 @@ private class ProduceSignatureCall extends ProduceCryptoCall {
5149
* A config that tracks data flow from initializing a cipher for encryption
5250
* to producing a ciphertext using this cipher.
5351
*/
54-
private class InitializeEncryptorConfig extends DataFlow3::Configuration {
55-
InitializeEncryptorConfig() { this = "InitializeEncryptorConfig" }
56-
57-
override predicate isSource(DataFlow::Node source) {
52+
private module InitializeEncryptorConfig implements DataFlow::ConfigSig {
53+
predicate isSource(DataFlow::Node source) {
5854
exists(MethodAccess ma |
5955
ma.getMethod().hasQualifiedName("javax.crypto", "Cipher", "init") and
6056
ma.getArgument(0).(VarAccess).getVariable().hasName("ENCRYPT_MODE") and
6157
ma.getQualifier() = source.asExpr()
6258
)
6359
}
6460

65-
override predicate isSink(DataFlow::Node sink) {
61+
predicate isSink(DataFlow::Node sink) {
6662
exists(MethodAccess ma |
6763
ma.getMethod().hasQualifiedName("javax.crypto", "Cipher", "doFinal") and
6864
ma.getQualifier() = sink.asExpr()
6965
)
7066
}
7167
}
7268

69+
private module InitializeEncryptorFlow = DataFlow::Global<InitializeEncryptorConfig>;
70+
7371
/** A method call that produces a ciphertext. */
7472
private class ProduceCiphertextCall extends ProduceCryptoCall {
7573
ProduceCiphertextCall() {
@@ -90,9 +88,7 @@ private class ProduceCiphertextCall extends ProduceCryptoCall {
9088
this.getArgument(1) = output
9189
)
9290
) and
93-
exists(InitializeEncryptorConfig config |
94-
config.hasFlowTo(DataFlow3::exprNode(this.getQualifier()))
95-
)
91+
InitializeEncryptorFlow::flowToExpr(this.getQualifier())
9692
}
9793

9894
override string getResultType() { result = "ciphertext" }
@@ -151,16 +147,14 @@ private predicate updateMessageDigestStep(DataFlow2::Node fromNode, DataFlow2::N
151147
* A config that tracks data flow from remote user input to a cryptographic operation
152148
* such as cipher, MAC or signature.
153149
*/
154-
private class UserInputInCryptoOperationConfig extends TaintTracking2::Configuration {
155-
UserInputInCryptoOperationConfig() { this = "UserInputInCryptoOperationConfig" }
156-
157-
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
150+
private module UserInputInCryptoOperationConfig implements DataFlow::ConfigSig {
151+
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
158152

159-
override predicate isSink(DataFlow::Node sink) {
153+
predicate isSink(DataFlow::Node sink) {
160154
exists(ProduceCryptoCall call | call.getQualifier() = sink.asExpr())
161155
}
162156

163-
override predicate isAdditionalTaintStep(DataFlow2::Node fromNode, DataFlow2::Node toNode) {
157+
predicate isAdditionalFlowStep(DataFlow2::Node fromNode, DataFlow2::Node toNode) {
164158
updateCryptoOperationStep(fromNode, toNode)
165159
or
166160
createMessageDigestStep(fromNode, toNode)
@@ -169,6 +163,13 @@ private class UserInputInCryptoOperationConfig extends TaintTracking2::Configura
169163
}
170164
}
171165

166+
/**
167+
* Taint-tracking flow from remote user input to a cryptographic operation
168+
* such as cipher, MAC or signature.
169+
*/
170+
private module UserInputInCryptoOperationFlow =
171+
TaintTracking::Global<UserInputInCryptoOperationConfig>;
172+
172173
/** A source that produces result of cryptographic operation. */
173174
class CryptoOperationSource extends DataFlow::Node {
174175
ProduceCryptoCall call;
@@ -177,8 +178,8 @@ class CryptoOperationSource extends DataFlow::Node {
177178

178179
/** Holds if remote user input was used in the cryptographic operation. */
179180
predicate includesUserInput() {
180-
exists(DataFlow2::PathNode sink, UserInputInCryptoOperationConfig config |
181-
config.hasFlowPath(_, sink)
181+
exists(UserInputInCryptoOperationFlow::PathNode sink |
182+
UserInputInCryptoOperationFlow::flowPath(_, sink)
182183
|
183184
sink.getNode().asExpr() = call.getQualifier()
184185
)
@@ -212,12 +213,10 @@ private class NonConstantTimeComparisonCall extends StaticMethodAccess {
212213
* A config that tracks data flow from remote user input to methods
213214
* that compare inputs using a non-constant-time algorithm.
214215
*/
215-
private class UserInputInComparisonConfig extends TaintTracking2::Configuration {
216-
UserInputInComparisonConfig() { this = "UserInputInComparisonConfig" }
216+
private module UserInputInComparisonConfig implements DataFlow::ConfigSig {
217+
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
217218

218-
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
219-
220-
override predicate isSink(DataFlow::Node sink) {
219+
predicate isSink(DataFlow::Node sink) {
221220
exists(NonConstantTimeEqualsCall call |
222221
sink.asExpr() = [call.getAnArgument(), call.getQualifier()]
223222
)
@@ -226,6 +225,8 @@ private class UserInputInComparisonConfig extends TaintTracking2::Configuration
226225
}
227226
}
228227

228+
private module UserInputInComparisonFlow = TaintTracking::Global<UserInputInComparisonConfig>;
229+
229230
/** Holds if `expr` looks like a constant. */
230231
private predicate looksLikeConstant(Expr expr) {
231232
expr.isCompileTimeConstant()
@@ -301,21 +302,18 @@ class NonConstantTimeComparisonSink extends DataFlow::Node {
301302
}
302303

303304
/** Holds if remote user input was used in the comparison. */
304-
predicate includesUserInput() {
305-
exists(UserInputInComparisonConfig config |
306-
config.hasFlowTo(DataFlow2::exprNode(anotherParameter))
307-
)
308-
}
305+
predicate includesUserInput() { UserInputInComparisonFlow::flowToExpr(anotherParameter) }
309306
}
310307

311308
/**
312309
* A configuration that tracks data flow from cryptographic operations
313310
* to methods that compare data using a non-constant-time algorithm.
314311
*/
315-
class NonConstantTimeCryptoComparisonConfig extends TaintTracking::Configuration {
316-
NonConstantTimeCryptoComparisonConfig() { this = "NonConstantTimeCryptoComparisonConfig" }
317-
318-
override predicate isSource(DataFlow::Node source) { source instanceof CryptoOperationSource }
312+
module NonConstantTimeCryptoComparisonConfig implements DataFlow::ConfigSig {
313+
predicate isSource(DataFlow::Node source) { source instanceof CryptoOperationSource }
319314

320-
override predicate isSink(DataFlow::Node sink) { sink instanceof NonConstantTimeComparisonSink }
315+
predicate isSink(DataFlow::Node sink) { sink instanceof NonConstantTimeComparisonSink }
321316
}
317+
318+
module NonConstantTimeCryptoComparisonFlow =
319+
TaintTracking::Global<NonConstantTimeCryptoComparisonConfig>;

java/ql/src/experimental/Security/CWE/CWE-208/PossibleTimingAttackAgainstSignature.ql

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515

1616
import java
1717
import NonConstantTimeCheckOnSignatureQuery
18-
import DataFlow::PathGraph
18+
import NonConstantTimeCryptoComparisonFlow::PathGraph
1919

20-
from DataFlow::PathNode source, DataFlow::PathNode sink, NonConstantTimeCryptoComparisonConfig conf
21-
where conf.hasFlowPath(source, sink)
20+
from
21+
NonConstantTimeCryptoComparisonFlow::PathNode source,
22+
NonConstantTimeCryptoComparisonFlow::PathNode sink
23+
where NonConstantTimeCryptoComparisonFlow::flowPath(source, sink)
2224
select sink.getNode(), source, sink, "Possible timing attack against $@ validation.", source,
2325
source.getNode().(CryptoOperationSource).getCall().getResultType()

java/ql/src/experimental/Security/CWE/CWE-208/TimingAttackAgainstSignature.ql

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616

1717
import java
1818
import NonConstantTimeCheckOnSignatureQuery
19-
import DataFlow::PathGraph
19+
import NonConstantTimeCryptoComparisonFlow::PathGraph
2020

21-
from DataFlow::PathNode source, DataFlow::PathNode sink, NonConstantTimeCryptoComparisonConfig conf
21+
from
22+
NonConstantTimeCryptoComparisonFlow::PathNode source,
23+
NonConstantTimeCryptoComparisonFlow::PathNode sink
2224
where
23-
conf.hasFlowPath(source, sink) and
25+
NonConstantTimeCryptoComparisonFlow::flowPath(source, sink) and
2426
(
2527
source.getNode().(CryptoOperationSource).includesUserInput() and
2628
sink.getNode().(NonConstantTimeComparisonSink).includesUserInput()

0 commit comments

Comments
 (0)