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

Skip to content

Commit 37d8558

Browse files
Jami CogswellJami Cogswell
authored andcommitted
refactor code into InsufficientKeySize.qll
1 parent 0fc4a33 commit 37d8558

5 files changed

Lines changed: 165 additions & 129 deletions

File tree

java/ql/lib/semmle/code/java/security/Encryption.qll

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,27 @@ class KeyGenerator extends RefType {
8383
KeyGenerator() { this.hasQualifiedName("javax.crypto", "KeyGenerator") }
8484
}
8585

86+
/** The `init` method declared in `javax.crypto.KeyGenerator`. */
87+
class KeyGeneratorInitMethod extends Method {
88+
KeyGeneratorInitMethod() {
89+
this.getDeclaringType() instanceof KeyGenerator and
90+
this.hasName("init")
91+
}
92+
}
93+
8694
/** The Java class `java.security.KeyPairGenerator`. */
8795
class KeyPairGenerator extends RefType {
8896
KeyPairGenerator() { this.hasQualifiedName("java.security", "KeyPairGenerator") }
8997
}
9098

99+
/** The `initialize` method declared in `java.security.KeyPairGenerator`. */
100+
class KeyPairGeneratorInitMethod extends Method {
101+
KeyPairGeneratorInitMethod() {
102+
this.getDeclaringType() instanceof KeyPairGenerator and
103+
this.hasName("initialize")
104+
}
105+
}
106+
91107
/** The `verify` method of the class `javax.net.ssl.HostnameVerifier`. */
92108
class HostnameVerifierVerify extends Method {
93109
HostnameVerifierVerify() {
@@ -307,6 +323,12 @@ class JavaxCryptoSecretKey extends JavaxCryptoAlgoSpec {
307323
}
308324
}
309325

326+
// TODO: consider extending JavaxCryptoAlgoSpec as above does; will need to override getAlgoSpec() method
327+
/** The Java class `javax.crypto.spec.DHGenParameterSpec`. */
328+
class DhGenParameterSpec extends RefType {
329+
DhGenParameterSpec() { this.hasQualifiedName("javax.crypto.spec", "DHGenParameterSpec") }
330+
}
331+
310332
class JavaxCryptoKeyGenerator extends JavaxCryptoAlgoSpec {
311333
JavaxCryptoKeyGenerator() {
312334
exists(Method m | m.getAReference() = this |
@@ -367,6 +389,24 @@ class JavaSecuritySignature extends JavaSecurityAlgoSpec {
367389
override Expr getAlgoSpec() { result = this.(ConstructorCall).getArgument(0) }
368390
}
369391

392+
// TODO: consider extending JavaSecurityAlgoSpec as above does; will need to override getAlgoSpec() method
393+
/** The Java class `java.security.spec.ECGenParameterSpec`. */
394+
class EcGenParameterSpec extends RefType {
395+
EcGenParameterSpec() { this.hasQualifiedName("java.security.spec", "ECGenParameterSpec") }
396+
}
397+
398+
// TODO: consider extending JavaSecurityAlgoSpec as above does; will need to override getAlgoSpec() method
399+
/** The Java class `java.security.spec.RSAKeyGenParameterSpec`. */
400+
class RsaKeyGenParameterSpec extends RefType {
401+
RsaKeyGenParameterSpec() { this.hasQualifiedName("java.security.spec", "RSAKeyGenParameterSpec") }
402+
}
403+
404+
// TODO: consider extending JavaSecurityAlgoSpec as above does; will need to override getAlgoSpec() method
405+
/** The Java class `java.security.spec.DSAGenParameterSpec`. */
406+
class DsaGenParameterSpec extends RefType {
407+
DsaGenParameterSpec() { this.hasQualifiedName("java.security.spec", "DSAGenParameterSpec") }
408+
}
409+
370410
/** A method call to the Java class `java.security.KeyPairGenerator`. */
371411
class JavaSecurityKeyPairGenerator extends JavaxCryptoAlgoSpec {
372412
JavaSecurityKeyPairGenerator() {
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/** Provides classes and predicates related to insufficient key sizes in Java. */
2+
3+
private import semmle.code.java.security.Encryption
4+
private import semmle.code.java.dataflow.DataFlow
5+
6+
/** A source for an insufficient key size. */
7+
abstract class InsufficientKeySizeSource extends DataFlow::Node { }
8+
9+
/** A sink for an insufficient key size. */
10+
abstract class InsufficientKeySizeSink extends DataFlow::Node { }
11+
12+
// TODO: Consider if below 3 sources should be private and if it's possible to only use InsufficientKeySizeSource in the configs
13+
// TODO: add QLDocs if keeping non-private
14+
class AsymmetricNonECSource extends InsufficientKeySizeSource {
15+
AsymmetricNonECSource() { getNodeIntValue(this) < 2048 }
16+
}
17+
18+
class AsymmetricECSource extends InsufficientKeySizeSource {
19+
AsymmetricECSource() {
20+
getNodeIntValue(this) < 256 or
21+
getECKeySize(this.asExpr().(StringLiteral).getValue()) < 256 // need this for the cases when the key size is embedded in the curve name.
22+
}
23+
}
24+
25+
class SymmetricSource extends InsufficientKeySizeSource {
26+
SymmetricSource() { getNodeIntValue(this) < 128 }
27+
}
28+
29+
private int getNodeIntValue(DataFlow::Node node) {
30+
result = node.asExpr().(IntegerLiteral).getIntValue()
31+
}
32+
33+
/** Returns the key size in the EC algorithm string */
34+
bindingset[algorithm]
35+
private int getECKeySize(string algorithm) {
36+
algorithm.matches("sec%") and // specification such as "secp256r1"
37+
result = algorithm.regexpCapture("sec[p|t](\\d+)[a-zA-Z].*", 1).toInt()
38+
or
39+
algorithm.matches("X9.62%") and //specification such as "X9.62 prime192v2"
40+
result = algorithm.regexpCapture("X9\\.62 .*[a-zA-Z](\\d+)[a-zA-Z].*", 1).toInt()
41+
or
42+
(algorithm.matches("prime%") or algorithm.matches("c2tnb%")) and //specification such as "prime192v2"
43+
result = algorithm.regexpCapture(".*[a-zA-Z](\\d+)[a-zA-Z].*", 1).toInt()
44+
}
45+
46+
class AsymmetricNonECSink extends InsufficientKeySizeSink {
47+
AsymmetricNonECSink() {
48+
exists(MethodAccess ma, JavaSecurityKeyPairGenerator jpg |
49+
ma.getMethod() instanceof KeyPairGeneratorInitMethod and
50+
jpg.getAlgoSpec().(StringLiteral).getValue().toUpperCase().matches(["RSA", "DSA", "DH"]) and
51+
DataFlow::localExprFlow(jpg, ma.getQualifier()) and
52+
this.asExpr() = ma.getArgument(0)
53+
)
54+
or
55+
exists(ClassInstanceExpr genParamSpec |
56+
genParamSpec.getConstructedType() instanceof AsymmetricNonECSpec and
57+
this.asExpr() = genParamSpec.getArgument(0)
58+
)
59+
}
60+
}
61+
62+
// TODO: move to Encryption.qll? or keep here since specific to this query?
63+
private class AsymmetricNonECSpec extends RefType {
64+
AsymmetricNonECSpec() {
65+
this instanceof RsaKeyGenParameterSpec or
66+
this instanceof DsaGenParameterSpec or
67+
this instanceof DhGenParameterSpec
68+
}
69+
}
70+
71+
class AsymmetricECSink extends InsufficientKeySizeSink {
72+
AsymmetricECSink() {
73+
exists(MethodAccess ma, JavaSecurityKeyPairGenerator jpg |
74+
ma.getMethod() instanceof KeyPairGeneratorInitMethod and
75+
jpg.getAlgoSpec().(StringLiteral).getValue().toUpperCase().matches("EC%") and
76+
DataFlow::localExprFlow(jpg, ma.getQualifier()) and
77+
this.asExpr() = ma.getArgument(0)
78+
)
79+
or
80+
exists(ClassInstanceExpr ecGenParamSpec |
81+
ecGenParamSpec.getConstructedType() instanceof EcGenParameterSpec and
82+
this.asExpr() = ecGenParamSpec.getArgument(0)
83+
)
84+
}
85+
}
86+
87+
class SymmetricSink extends InsufficientKeySizeSink {
88+
SymmetricSink() {
89+
exists(MethodAccess ma, JavaxCryptoKeyGenerator jcg |
90+
ma.getMethod() instanceof KeyGeneratorInitMethod and
91+
jcg.getAlgoSpec().(StringLiteral).getValue().toUpperCase() = "AES" and
92+
DataFlow::localExprFlow(jcg, ma.getQualifier()) and
93+
this.asExpr() = ma.getArgument(0)
94+
)
95+
}
96+
}
97+
// TODO:
98+
// todo #0: look into use of specs without keygen objects; should spec not be a sink in these cases?
99+
// todo #3: make list of algo names more easily reusable (either as constant-type variable at top of file, or model as own class to share, etc.)
100+
// todo #5:

java/ql/lib/semmle/code/java/security/InsufficientKeySizeQuery.qll

Lines changed: 14 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,148 +1,43 @@
1-
/** Provides classes and predicates related to insufficient key sizes in Java. */
1+
/** Provides data flow configurations to be used in queries related to insufficient key sizes. */
22

33
import semmle.code.java.security.Encryption
44
import semmle.code.java.dataflow.DataFlow
55
import semmle.code.java.dataflow.TaintTracking
6+
import semmle.code.java.security.InsufficientKeySize
67

78
/**
8-
* An Asymmetric (RSA, DSA, DH) key length data flow tracking configuration.
9+
* A data flow configuration for tracking non-elliptic curve asymmetric algorithms
10+
* (RSA, DSA, and DH) key sizes.
911
*/
1012
class AsymmetricNonECKeyTrackingConfiguration extends DataFlow::Configuration {
1113
AsymmetricNonECKeyTrackingConfiguration() { this = "AsymmetricNonECKeyTrackingConfiguration" }
1214

13-
override predicate isSource(DataFlow::Node source) {
14-
source.asExpr().(IntegerLiteral).getIntValue() < 2048
15-
}
15+
override predicate isSource(DataFlow::Node source) { source instanceof AsymmetricNonECSource }
1616

17-
override predicate isSink(DataFlow::Node sink) {
18-
exists(MethodAccess ma, JavaSecurityKeyPairGenerator jpg |
19-
ma.getMethod() instanceof KeyPairGeneratorInitMethod and
20-
jpg.getAlgoSpec().(StringLiteral).getValue().toUpperCase().matches(["RSA", "DSA", "DH"]) and
21-
DataFlow::localExprFlow(jpg, ma.getQualifier()) and
22-
sink.asExpr() = ma.getArgument(0)
23-
)
24-
or
25-
// TODO: combine below three for less duplicated code
26-
exists(ClassInstanceExpr rsaKeyGenParamSpec |
27-
rsaKeyGenParamSpec.getConstructedType() instanceof RsaKeyGenParameterSpec and
28-
sink.asExpr() = rsaKeyGenParamSpec.getArgument(0)
29-
)
30-
or
31-
exists(ClassInstanceExpr dsaGenParamSpec |
32-
dsaGenParamSpec.getConstructedType() instanceof DsaGenParameterSpec and
33-
sink.asExpr() = dsaGenParamSpec.getArgument(0)
34-
)
35-
or
36-
exists(ClassInstanceExpr dhGenParamSpec |
37-
dhGenParamSpec.getConstructedType() instanceof DhGenParameterSpec and
38-
sink.asExpr() = dhGenParamSpec.getArgument(0)
39-
)
40-
}
17+
override predicate isSink(DataFlow::Node sink) { sink instanceof AsymmetricNonECSink }
4118
}
4219

4320
/**
44-
* An Asymmetric (EC) key length data flow tracking configuration.
21+
* A data flow configuration for tracking elliptic curve (EC) asymmetric
22+
* algorithm key sizes.
4523
*/
4624
class AsymmetricECKeyTrackingConfiguration extends DataFlow::Configuration {
4725
AsymmetricECKeyTrackingConfiguration() { this = "AsymmetricECKeyTrackingConfiguration" }
4826

49-
override predicate isSource(DataFlow::Node source) {
50-
source.asExpr().(IntegerLiteral).getIntValue() < 256 or
51-
getECKeySize(source.asExpr().(StringLiteral).getValue()) < 256 // need this for the cases when the key size is embedded in the curve name.
52-
}
27+
override predicate isSource(DataFlow::Node source) { source instanceof AsymmetricECSource }
5328

54-
override predicate isSink(DataFlow::Node sink) {
55-
exists(MethodAccess ma, JavaSecurityKeyPairGenerator jpg |
56-
ma.getMethod() instanceof KeyPairGeneratorInitMethod and
57-
jpg.getAlgoSpec().(StringLiteral).getValue().toUpperCase().matches("EC%") and
58-
DataFlow::localExprFlow(jpg, ma.getQualifier()) and
59-
sink.asExpr() = ma.getArgument(0)
60-
)
61-
or
62-
exists(ClassInstanceExpr ecGenParamSpec |
63-
ecGenParamSpec.getConstructedType() instanceof EcGenParameterSpec and
64-
sink.asExpr() = ecGenParamSpec.getArgument(0)
65-
)
66-
}
29+
override predicate isSink(DataFlow::Node sink) { sink instanceof AsymmetricECSink }
6730
}
6831

69-
/**
70-
* A Symmetric (AES) key length data flow tracking configuration.
71-
*/
32+
/** A data flow configuration for tracking symmetric algorithm (AES) key sizes. */
7233
class SymmetricKeyTrackingConfiguration extends DataFlow::Configuration {
7334
SymmetricKeyTrackingConfiguration() { this = "SymmetricKeyTrackingConfiguration" }
7435

75-
override predicate isSource(DataFlow::Node source) {
76-
source.asExpr().(IntegerLiteral).getIntValue() < 128
77-
}
78-
79-
override predicate isSink(DataFlow::Node sink) {
80-
exists(MethodAccess ma, JavaxCryptoKeyGenerator jcg |
81-
ma.getMethod() instanceof KeyGeneratorInitMethod and
82-
jcg.getAlgoSpec().(StringLiteral).getValue().toUpperCase() = "AES" and
83-
DataFlow::localExprFlow(jcg, ma.getQualifier()) and
84-
sink.asExpr() = ma.getArgument(0)
85-
)
86-
}
87-
}
88-
89-
// ********************** Need the below models for the above configs **********************
90-
// todo: move some/all of below to Encryption.qll or elsewhere?
91-
/** The Java class `java.security.spec.ECGenParameterSpec`. */
92-
private class EcGenParameterSpec extends RefType {
93-
EcGenParameterSpec() { this.hasQualifiedName("java.security.spec", "ECGenParameterSpec") }
94-
}
95-
96-
/** The Java class `java.security.spec.RSAKeyGenParameterSpec`. */
97-
private class RsaKeyGenParameterSpec extends RefType {
98-
RsaKeyGenParameterSpec() { this.hasQualifiedName("java.security.spec", "RSAKeyGenParameterSpec") }
99-
}
100-
101-
/** The Java class `java.security.spec.DSAGenParameterSpec`. */
102-
private class DsaGenParameterSpec extends RefType {
103-
DsaGenParameterSpec() { this.hasQualifiedName("java.security.spec", "DSAGenParameterSpec") }
104-
}
105-
106-
/** The Java class `javax.crypto.spec.DHGenParameterSpec`. */
107-
private class DhGenParameterSpec extends RefType {
108-
DhGenParameterSpec() { this.hasQualifiedName("javax.crypto.spec", "DHGenParameterSpec") }
109-
}
110-
111-
/** The `init` method declared in `javax.crypto.KeyGenerator`. */
112-
private class KeyGeneratorInitMethod extends Method {
113-
KeyGeneratorInitMethod() {
114-
this.getDeclaringType() instanceof KeyGenerator and
115-
this.hasName("init")
116-
}
117-
}
118-
119-
/** The `initialize` method declared in `java.security.KeyPairGenerator`. */
120-
private class KeyPairGeneratorInitMethod extends Method {
121-
KeyPairGeneratorInitMethod() {
122-
this.getDeclaringType() instanceof KeyPairGenerator and
123-
this.hasName("initialize")
124-
}
125-
}
36+
override predicate isSource(DataFlow::Node source) { source instanceof SymmetricSource }
12637

127-
/** Returns the key size in the EC algorithm string */
128-
bindingset[algorithm]
129-
private int getECKeySize(string algorithm) {
130-
algorithm.matches("sec%") and // specification such as "secp256r1"
131-
result = algorithm.regexpCapture("sec[p|t](\\d+)[a-zA-Z].*", 1).toInt()
132-
or
133-
algorithm.matches("X9.62%") and //specification such as "X9.62 prime192v2"
134-
result = algorithm.regexpCapture("X9\\.62 .*[a-zA-Z](\\d+)[a-zA-Z].*", 1).toInt()
135-
or
136-
(algorithm.matches("prime%") or algorithm.matches("c2tnb%")) and //specification such as "prime192v2"
137-
result = algorithm.regexpCapture(".*[a-zA-Z](\\d+)[a-zA-Z].*", 1).toInt()
38+
override predicate isSink(DataFlow::Node sink) { sink instanceof SymmetricSink }
13839
}
139-
// ******* DATAFLOW ABOVE *************************************************************************
140-
// TODO:
141-
// todo #0: look into use of specs without keygens; should spec not be a sink in these cases?
142-
// todo #1: make representation of source that can be shared across the configs
143-
// todo #2: make representation of sink that can be shared across the configs
144-
// todo #3: make list of algo names more easily reusable (either as constant-type variable at top of file, or model as own class to share, etc.)
145-
// todo #4: refactor to be more like the Python (or C#) version? (or not possible because of lack of DataFlow::Node for void method in Java?)
40+
// ******* 3 DATAFLOW CONFIGS ABOVE *************************************************************************
14641
// ******* SINGLE CONFIG ATTEMPT BELOW *************************************************************************
14742
// /**
14843
// * A key length data flow tracking configuration.

java/ql/src/Security/CWE/CWE-326/InsufficientKeySize.ql

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ import semmle.code.java.security.InsufficientKeySizeQuery
1616
import DataFlow::PathGraph
1717

1818
from DataFlow::PathNode source, DataFlow::PathNode sink
19-
where exists(KeyTrackingConfiguration config1 | config1.hasFlowPath(source, sink))
20-
//or
21-
// exists(AsymmetricNonECKeyTrackingConfiguration config1 | config1.hasFlowPath(source, sink)) or
22-
// exists(AsymmetricECKeyTrackingConfiguration config2 | config2.hasFlowPath(source, sink)) or
23-
// exists(SymmetricKeyTrackingConfiguration config3 | config3.hasFlowPath(source, sink))
19+
where
20+
//exists(KeyTrackingConfiguration config1 | config1.hasFlowPath(source, sink))
21+
//or
22+
exists(AsymmetricNonECKeyTrackingConfiguration config1 | config1.hasFlowPath(source, sink)) or
23+
exists(AsymmetricECKeyTrackingConfiguration config2 | config2.hasFlowPath(source, sink)) or
24+
exists(SymmetricKeyTrackingConfiguration config3 | config3.hasFlowPath(source, sink))
2425
select sink.getNode(), source, sink, "This $@ is too small.", source.getNode(), "key size"

java/ql/test/query-tests/security/CWE-326/InsufficientKeySizeTest.ql

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ class InsufficientKeySizeTest extends InlineExpectationsTest {
1111
override predicate hasActualResult(Location location, string element, string tag, string value) {
1212
tag = "hasInsufficientKeySize" and
1313
exists(DataFlow::PathNode source, DataFlow::PathNode sink |
14-
exists(KeyTrackingConfiguration config1 | config1.hasFlowPath(source, sink))
15-
|
14+
//exists(KeyTrackingConfiguration config1 | config1.hasFlowPath(source, sink))
1615
//or
17-
// exists(AsymmetricNonECKeyTrackingConfiguration config1 | config1.hasFlowPath(source, sink)) or
18-
// exists(AsymmetricECKeyTrackingConfiguration config2 | config2.hasFlowPath(source, sink)) or
19-
//exists(SymmetricKeyTrackingConfiguration config3 | config3.hasFlowPath(source, sink))
16+
exists(AsymmetricNonECKeyTrackingConfiguration config1 | config1.hasFlowPath(source, sink)) or
17+
exists(AsymmetricECKeyTrackingConfiguration config2 | config2.hasFlowPath(source, sink)) or
18+
exists(SymmetricKeyTrackingConfiguration config3 | config3.hasFlowPath(source, sink))
19+
|
2020
sink.getNode().getLocation() = location and
2121
element = sink.getNode().toString() and
2222
value = ""

0 commit comments

Comments
 (0)