1
- private import codeql.ruby.AST
2
- import codeql.ruby.AST
3
- import codeql.ruby.DataFlow
1
+ /**
2
+ * @name Unsafe HMAC Comparison
3
+ * @description An HMAC is being compared using the equality operator. This may be vulnerable to a cryptographic timing attack
4
+ * because the equality operation does not occur in constant time."
5
+
6
+ * @kind path-problem
7
+ * @problem.severity error
8
+ * @security-severity 6.0
9
+ * @precision high
10
+ * @id rb/unsafe-hmac-comparison
11
+ * @tags security
12
+ * external/cwe/cwe-208
13
+ */
14
+
15
+
16
+ private import codeql.ruby.DataFlow
4
17
import codeql.ruby.ApiGraphs
5
- import codeql.ruby.dataflow.RemoteFlowSources
6
- import codeql.ruby.TaintTracking
7
18
import ruby
8
19
9
- // A call to OpenSSL::HMAC.hexdigest
10
- class OpenSslHmacHexdigest extends DataFlow:: Node {
11
- OpenSslHmacHexdigest ( ) {
12
- this = API:: getTopLevelMember ( "OpenSSL" ) .getMember ( "HMAC" ) .getAMethodCall ( "hexdigest" )
20
+ private class OpenSslHmacSource extends DataFlow:: Node {
21
+ OpenSslHmacSource ( ) {
22
+ exists ( API:: Node hmacNode | hmacNode = API:: getTopLevelMember ( "OpenSSL" ) .getMember ( "HMAC" ) |
23
+ this = hmacNode .getAMethodCall ( [ "hexdigest" , "to_s" , "digest" , "base64digest" ] )
24
+ or
25
+ this = hmacNode .getAnInstantiation ( )
26
+ )
13
27
}
14
28
}
15
29
16
- // A call to OpenSSL::HMAC.to_s (which is an alias for OpenSSL::HMAC.hexdigest)
17
- class OpenSslHmactos extends DataFlow:: Node {
18
- OpenSslHmactos ( ) {
19
- this = API:: getTopLevelMember ( "OpenSSL" ) .getMember ( "HMAC" ) .getAMethodCall ( "to_s" )
20
- }
21
- }
22
-
23
- // A call to OpenSSL::HMAC.digest
24
- class OpenSslHmacdigest extends DataFlow:: Node {
25
- OpenSslHmacdigest ( ) {
26
- this = API:: getTopLevelMember ( "OpenSSL" ) .getMember ( "HMAC" ) .getAMethodCall ( "digest" )
27
- }
28
- }
29
-
30
- // A call to OpenSSL::HMAC.new
31
- class OpenSslnewHmac extends DataFlow:: Node {
32
- OpenSslnewHmac ( ) {
33
- this = API:: getTopLevelMember ( "OpenSSL" ) .getMember ( "HMAC" ) .getAnInstantiation ( )
34
- }
35
- }
36
-
37
- // A call to OpenSSL::HMAC.base64digest
38
- class OpenSslHmacbase64digest extends DataFlow:: Node {
39
- OpenSslHmacbase64digest ( ) {
40
- this = API:: getTopLevelMember ( "OpenSSL" ) .getMember ( "HMAC" ) .getAMethodCall ( "base64digest" )
41
- }
42
- }
43
-
44
- class Configuration extends DataFlow:: Configuration {
45
- Configuration ( ) { this = "UnsafeHmacComparison" }
46
-
47
- override predicate isSource ( DataFlow:: Node source ) {
48
- source instanceof OpenSslHmacHexdigest or
49
- source instanceof OpenSslnewHmac or
50
- source instanceof OpenSslHmacbase64digest or
51
- source instanceof OpenSslHmacdigest or
52
- source instanceof OpenSslHmactos
53
- }
30
+ private module UnsafeHmacComparison {
31
+ private module Config implements DataFlow:: ConfigSig {
32
+ predicate isSource ( DataFlow:: Node source ) {
33
+ source instanceof OpenSslHmacSource
34
+ }
54
35
55
36
// Holds if a given sink is an Equality Operation (== or !=)
56
- override predicate isSink ( DataFlow:: Node sink ) {
37
+ predicate isSink ( DataFlow:: Node sink ) {
57
38
any ( EqualityOperation eqOp ) .getAnOperand ( ) = sink .asExpr ( ) .getExpr ( )
58
39
}
40
+ }
41
+
42
+ import DataFlow:: Global< Config >
59
43
}
60
44
61
- from DataFlow:: Node source , DataFlow:: Node sink , Configuration config
62
- where config .hasFlow ( source , sink )
63
- select sink ,
64
- "An HMAC is being compared using the equality operator. This may be vulnerable to a cryptographic timing attack because the equality operation does not occur in constant time."
45
+ from UnsafeHmacComparison:: PathNode source , UnsafeHmacComparison:: PathNode sink
46
+ where UnsafeHmacComparison:: flowPath ( source , sink )
47
+ select sink .getNode ( ) , source , sink , "This comparison is potentially vulnerable to a timing attack."
0 commit comments