Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 46ad611

Browse files
committed
Python: Port py/weak-crypto-key to use type-tracking
instead of points-to. Looking at query results also made me realize I didn't supply a very good "origin" for ECC in cryptography package, so I improved that 👍 -- maybe that sohuld have been split into multiple commits... too late :(
1 parent 2429c6c commit 46ad611

5 files changed

Lines changed: 102 additions & 78 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* Ported _Use of weak cryptographic key_ (`py/weak-crypto-key`) query to use new type-tracking approach instead of points-to. This might result in some difference in results being found, but overall this should result in a more robust and accurate analysis.

python/ql/src/Security/CWE-326/WeakCrypto.ql

Lines changed: 8 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -10,72 +10,13 @@
1010
*/
1111

1212
import python
13+
import semmle.python.Concepts
14+
import semmle.python.dataflow.new.DataFlow
1315

14-
int minimumSecureKeySize(string algo) {
15-
algo = "DSA" and result = 2048
16-
or
17-
algo = "RSA" and result = 2048
18-
or
19-
algo = "ECC" and result = 224
20-
}
21-
22-
predicate dsaRsaKeySizeArg(FunctionValue func, string algorithm, string arg) {
23-
exists(ModuleValue mod | func = mod.attr(_) |
24-
algorithm = "DSA" and
25-
(
26-
mod = Module::named("cryptography.hazmat.primitives.asymmetric.dsa") and arg = "key_size"
27-
or
28-
mod = Module::named("Crypto.PublicKey.DSA") and arg = "bits"
29-
or
30-
mod = Module::named("Cryptodome.PublicKey.DSA") and arg = "bits"
31-
)
32-
or
33-
algorithm = "RSA" and
34-
(
35-
mod = Module::named("cryptography.hazmat.primitives.asymmetric.rsa") and arg = "key_size"
36-
or
37-
mod = Module::named("Crypto.PublicKey.RSA") and arg = "bits"
38-
or
39-
mod = Module::named("Cryptodome.PublicKey.RSA") and arg = "bits"
40-
)
41-
)
42-
}
43-
44-
predicate ecKeySizeArg(FunctionValue func, string arg) {
45-
exists(ModuleValue mod | func = mod.attr(_) |
46-
mod = Module::named("cryptography.hazmat.primitives.asymmetric.ec") and arg = "curve"
47-
)
48-
}
49-
50-
int keySizeFromCurve(ClassValue curveClass) {
51-
result = curveClass.declaredAttribute("key_size").(NumericValue).getIntValue()
52-
}
53-
54-
predicate algorithmAndKeysizeForCall(
55-
CallNode call, string algorithm, int keySize, ControlFlowNode keyOrigin
56-
) {
57-
exists(FunctionValue func, string argname, ControlFlowNode arg |
58-
arg = func.getNamedArgumentForCall(call, argname)
59-
|
60-
exists(NumericValue key |
61-
arg.pointsTo(key, keyOrigin) and
62-
dsaRsaKeySizeArg(func, algorithm, argname) and
63-
keySize = key.getIntValue()
64-
)
65-
or
66-
exists(Value curveClassInstance |
67-
algorithm = "ECC" and
68-
ecKeySizeArg(func, argname) and
69-
arg.pointsTo(_, curveClassInstance, keyOrigin) and
70-
keySize = keySizeFromCurve(curveClassInstance.getClass())
71-
)
72-
)
73-
}
74-
75-
from CallNode call, string algo, int keySize, ControlFlowNode origin
16+
from Cryptography::PublicKey::KeyGeneration keyGen, int keySize, DataFlow::Node origin
7617
where
77-
algorithmAndKeysizeForCall(call, algo, keySize, origin) and
78-
keySize < minimumSecureKeySize(algo)
79-
select call,
80-
"Creation of an " + algo + " key uses $@ bits, which is below " + minimumSecureKeySize(algo) +
81-
" and considered breakable.", origin, keySize.toString()
18+
keySize = keyGen.getKeySizeWithOrigin(origin) and
19+
keySize < keyGen.minimumSecureKeySize()
20+
select keyGen,
21+
"Creation of an " + keyGen.getName() + " key uses $@ bits, which is below " +
22+
keyGen.minimumSecureKeySize() + " and considered breakable.", origin, keySize.toString()
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
* @name Use of weak cryptographic key
3+
* @description Use of a cryptographic key that is too small may allow the encryption to be broken.
4+
* @kind problem
5+
* @problem.severity error
6+
* @precision high
7+
* @id py/weak-crypto-key
8+
* @tags security
9+
* external/cwe/cwe-326
10+
*/
11+
12+
import python
13+
14+
int minimumSecureKeySize(string algo) {
15+
algo = "DSA" and result = 2048
16+
or
17+
algo = "RSA" and result = 2048
18+
or
19+
algo = "ECC" and result = 224
20+
}
21+
22+
predicate dsaRsaKeySizeArg(FunctionValue func, string algorithm, string arg) {
23+
exists(ModuleValue mod | func = mod.attr(_) |
24+
algorithm = "DSA" and
25+
(
26+
mod = Module::named("cryptography.hazmat.primitives.asymmetric.dsa") and arg = "key_size"
27+
or
28+
mod = Module::named("Crypto.PublicKey.DSA") and arg = "bits"
29+
or
30+
mod = Module::named("Cryptodome.PublicKey.DSA") and arg = "bits"
31+
)
32+
or
33+
algorithm = "RSA" and
34+
(
35+
mod = Module::named("cryptography.hazmat.primitives.asymmetric.rsa") and arg = "key_size"
36+
or
37+
mod = Module::named("Crypto.PublicKey.RSA") and arg = "bits"
38+
or
39+
mod = Module::named("Cryptodome.PublicKey.RSA") and arg = "bits"
40+
)
41+
)
42+
}
43+
44+
predicate ecKeySizeArg(FunctionValue func, string arg) {
45+
exists(ModuleValue mod | func = mod.attr(_) |
46+
mod = Module::named("cryptography.hazmat.primitives.asymmetric.ec") and arg = "curve"
47+
)
48+
}
49+
50+
int keySizeFromCurve(ClassValue curveClass) {
51+
result = curveClass.declaredAttribute("key_size").(NumericValue).getIntValue()
52+
}
53+
54+
predicate algorithmAndKeysizeForCall(
55+
CallNode call, string algorithm, int keySize, ControlFlowNode keyOrigin
56+
) {
57+
exists(FunctionValue func, string argname, ControlFlowNode arg |
58+
arg = func.getNamedArgumentForCall(call, argname)
59+
|
60+
exists(NumericValue key |
61+
arg.pointsTo(key, keyOrigin) and
62+
dsaRsaKeySizeArg(func, algorithm, argname) and
63+
keySize = key.getIntValue()
64+
)
65+
or
66+
exists(Value curveClassInstance |
67+
algorithm = "ECC" and
68+
ecKeySizeArg(func, argname) and
69+
arg.pointsTo(_, curveClassInstance, keyOrigin) and
70+
keySize = keySizeFromCurve(curveClassInstance.getClass())
71+
)
72+
)
73+
}
74+
75+
from CallNode call, string algo, int keySize, ControlFlowNode origin
76+
where
77+
algorithmAndKeysizeForCall(call, algo, keySize, origin) and
78+
keySize < minimumSecureKeySize(algo)
79+
select call,
80+
"Creation of an " + algo + " key uses $@ bits, which is below " + minimumSecureKeySize(algo) +
81+
" and considered breakable.", origin, keySize.toString()

python/ql/src/semmle/python/frameworks/Cryptography.qll

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -423,22 +423,23 @@ private module CryptographyModel {
423423
result = ec_attr("BrainpoolP512R1") and keySize = 512
424424
}
425425

426-
/** Gets a predefined curve class instance with a specific key size (in bits). */
426+
/** Gets a reference to a predefined curve class instance with a specific key size (in bits), as well as the origin of the class. */
427427
private DataFlow::Node curveClassInstanceWithKeySize(
428-
DataFlow::TypeTracker t, int keySize
428+
DataFlow::TypeTracker t, int keySize, DataFlow::Node origin
429429
) {
430430
t.start() and
431431
result.asCfgNode().(CallNode).getFunction() =
432-
curveClassWithKeySize(keySize).asCfgNode()
432+
curveClassWithKeySize(keySize).asCfgNode() and
433+
origin = result
433434
or
434435
exists(DataFlow::TypeTracker t2 |
435-
result = curveClassInstanceWithKeySize(t2, keySize).track(t2, t)
436+
result = curveClassInstanceWithKeySize(t2, keySize, origin).track(t2, t)
436437
)
437438
}
438439

439-
/** Gets a predefined curve class instance with a specific key size (in bits). */
440-
DataFlow::Node curveClassInstanceWithKeySize(int keySize) {
441-
result = curveClassInstanceWithKeySize(DataFlow::TypeTracker::end(), keySize)
440+
/** Gets a reference to a predefined curve class instance with a specific key size (in bits), as well as the origin of the class. */
441+
DataFlow::Node curveClassInstanceWithKeySize(int keySize, DataFlow::Node origin) {
442+
result = curveClassInstanceWithKeySize(DataFlow::TypeTracker::end(), keySize, origin)
442443
}
443444
}
444445
}
@@ -505,9 +506,9 @@ private module CryptographyModel {
505506
}
506507

507508
override int getKeySizeWithOrigin(DataFlow::Node origin) {
508-
origin = this.getCurveArg() and
509-
origin =
510-
cryptography::hazmat::primitives::asymmetric::ec::curveClassInstanceWithKeySize(result)
509+
this.getCurveArg() =
510+
cryptography::hazmat::primitives::asymmetric::ec::curveClassInstanceWithKeySize(result,
511+
origin)
511512
}
512513

513514
// Note: There is not really a key-size argument, since it's always specified by the curve.

python/ql/test/query-tests/Security/CWE-326/options

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)