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
417import codeql.ruby.ApiGraphs
5- import codeql.ruby.dataflow.RemoteFlowSources
6- import codeql.ruby.TaintTracking
718import ruby
819
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+ )
1327 }
1428}
1529
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+ }
5435
5536 // Holds if a given sink is an Equality Operation (== or !=)
56- override predicate isSink ( DataFlow:: Node sink ) {
37+ predicate isSink ( DataFlow:: Node sink ) {
5738 any ( EqualityOperation eqOp ) .getAnOperand ( ) = sink .asExpr ( ) .getExpr ( )
5839 }
40+ }
41+
42+ import DataFlow:: Global< Config >
5943}
6044
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