Skip to content

Commit 1c7fe97

Browse files
committed
Python: Add modeling of hmac
1 parent df22181 commit 1c7fe97

File tree

3 files changed

+85
-8
lines changed

3 files changed

+85
-8
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added modeling of cryptographic operations in the `hmac` library.

python/ql/lib/semmle/python/frameworks/Stdlib.qll

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2669,6 +2669,7 @@ private module StdlibPrivate {
26692669

26702670
HashlibNewCall() {
26712671
this = hashlibNewCall(hashName) and
2672+
// we only want to consider it as an cryptographic operation if the input is available
26722673
exists(this.getParameter(1, "data"))
26732674
}
26742675

@@ -2751,6 +2752,78 @@ private module StdlibPrivate {
27512752
}
27522753
}
27532754

2755+
// ---------------------------------------------------------------------------
2756+
// hmac
2757+
// ---------------------------------------------------------------------------
2758+
abstract class HmacCryptographicOperation extends Cryptography::CryptographicOperation::Range,
2759+
API::CallNode {
2760+
abstract API::Node getDigestArg();
2761+
2762+
override Cryptography::CryptographicAlgorithm getAlgorithm() {
2763+
exists(string algorithmName | result.matchesName(algorithmName) |
2764+
this.getDigestArg().asSink() = hashlibMember(algorithmName).asSource()
2765+
or
2766+
this.getDigestArg().getAValueReachingSink().asExpr().(StrConst).getText() = algorithmName
2767+
)
2768+
}
2769+
2770+
override Cryptography::BlockMode getBlockMode() { none() }
2771+
}
2772+
2773+
API::CallNode getHmacConstructorCall(API::Node digestArg) {
2774+
result = API::moduleImport("hmac").getMember(["new", "HMAC"]).getACall() and
2775+
digestArg = result.getParameter(2, "digestmod")
2776+
}
2777+
2778+
/**
2779+
* A call to `hmac.new`/`hmac.HMAC`.
2780+
*
2781+
* See https://docs.python.org/3.11/library/hmac.html#hmac.new
2782+
*/
2783+
class HmacNewCall extends HmacCryptographicOperation {
2784+
API::Node digestArg;
2785+
2786+
HmacNewCall() {
2787+
this = getHmacConstructorCall(digestArg) and
2788+
// we only want to consider it as an cryptographic operation if the input is available
2789+
exists(this.getParameter(1, "msg").asSink())
2790+
}
2791+
2792+
override API::Node getDigestArg() { result = digestArg }
2793+
2794+
override DataFlow::Node getAnInput() { result = this.getParameter(1, "msg").asSink() }
2795+
}
2796+
2797+
/**
2798+
* A call to `.update` on an HMAC object.
2799+
*
2800+
* See https://docs.python.org/3.11/library/hmac.html#hmac.HMAC.update
2801+
*/
2802+
class HmacUpdateCall extends HmacCryptographicOperation {
2803+
API::Node digestArg;
2804+
2805+
HmacUpdateCall() {
2806+
this = getHmacConstructorCall(digestArg).getReturn().getMember("update").getACall()
2807+
}
2808+
2809+
override API::Node getDigestArg() { result = digestArg }
2810+
2811+
override DataFlow::Node getAnInput() { result = this.getParameter(0, "msg").asSink() }
2812+
}
2813+
2814+
/**
2815+
* A call to `hmac.digest`.
2816+
*
2817+
* See https://docs.python.org/3.11/library/hmac.html#hmac.digest
2818+
*/
2819+
class HmacDigestCall extends HmacCryptographicOperation {
2820+
HmacDigestCall() { this = API::moduleImport("hmac").getMember("digest").getACall() }
2821+
2822+
override API::Node getDigestArg() { result = this.getParameter(2, "digest") }
2823+
2824+
override DataFlow::Node getAnInput() { result = this.getParameter(1, "msg").asSink() }
2825+
}
2826+
27542827
// ---------------------------------------------------------------------------
27552828
// logging
27562829
// ---------------------------------------------------------------------------

python/ql/test/library-tests/frameworks/stdlib/test_hmac.py

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

44
key = b"<secret key>"
55

6-
hmac_obj = hmac.new(key, b"secret message", "sha256") # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256
6+
hmac_obj = hmac.new(key, b"secret message", "sha256") # $ CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256
77
print(hmac_obj.digest())
88
print(hmac_obj.hexdigest())
99

10-
hmac_obj = hmac.new(key, msg=b"secret message", digestmod="sha256") # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256
10+
hmac_obj = hmac.new(key, msg=b"secret message", digestmod="sha256") # $ CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256
1111
print(hmac_obj.hexdigest())
1212

1313

1414
hmac_obj = hmac.new(key, digestmod="sha256")
15-
hmac_obj.update(b"secret") # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret" CryptographicOperationAlgorithm=SHA256
16-
hmac_obj.update(msg=b" message") # $ MISSING: CryptographicOperation CryptographicOperationInput=b" message" CryptographicOperationAlgorithm=SHA256
15+
hmac_obj.update(b"secret") # $ CryptographicOperation CryptographicOperationInput=b"secret" CryptographicOperationAlgorithm=SHA256
16+
hmac_obj.update(msg=b" message") # $ CryptographicOperation CryptographicOperationInput=b" message" CryptographicOperationAlgorithm=SHA256
1717
print(hmac_obj.hexdigest())
1818

1919

20-
hmac_obj = hmac.new(key, b"secret message", hashlib.sha256) # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256
20+
hmac_obj = hmac.new(key, b"secret message", hashlib.sha256) # $ CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256
2121
print(hmac_obj.hexdigest())
2222

2323

2424
# like hmac.new
2525
hmac_obj = hmac.HMAC(key, digestmod="sha256")
26-
hmac_obj.update(b"secret message") # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256
26+
hmac_obj.update(b"secret message") # $ CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256
2727
print(hmac_obj.hexdigest())
2828

2929

30-
dig = hmac.digest(key, b"secret message", "sha256") # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256
30+
dig = hmac.digest(key, b"secret message", "sha256") # $ CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256
3131
print(dig)
32-
dig = hmac.digest(key, msg=b"secret message", digest="sha256") # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256
32+
dig = hmac.digest(key, msg=b"secret message", digest="sha256") # $ CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256
3333
print(dig)

0 commit comments

Comments
 (0)