-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Java: Promote insufficient key size query from experimental #10785
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
jcogs33
merged 59 commits into
github:main
from
jcogs33:insuff-key-size-globalflow-keysize
Nov 8, 2022
Merged
Changes from all commits
Commits
Show all changes
59 commits
Select commit
Hold shift + click to select a range
9b7df35
move files
3643c9e
update metadata
657e1e6
start refactoring query logic into lib file
9eb45c3
refactor tests and code, update help file
7d94590
add change note
75794ec
false negative testing - before rewrite for variable dataflow
7de9c05
use CompileTimeConstantExpr for FN with VarAccess, and remove KeyGene…
d3b1a04
handle FN case with simple VarAccess; add draft of dataflow config to…
8ffd252
add draft code to find algo type to replace tainttracking configs
ac70719
commit before adding taint flow back (since no taint flow doesn't cap…
5e2ef66
refactoring to use both dataflow configs; commit before deleting unus…
c414ee0
add ECC dataflow config; passes all test cases; still don't have algo…
cdac0e2
add local algo name tracking, still need to add ability to track algo…
b7123c1
draft of adding kpg tracking into dataflow config
b0af9f9
added kg taintracking config to all
f5a2fef
update tests for non-path version
3cc7f14
clean up code somewhat
0c2cff2
updates from discussing with Tony
bd76b1f
clean-up and update configurations to have specs as sink
b6a8c27
delete experimental files
e64825f
fix code-scanning bot problems
26f4abf
remove globalflow for key(pair)gen
3e8748e
add path-graph back to query alerts
29de0c6
make one config for asymm with flow states; seems to work...
01c2a8c
add symm to the single config; still seems to work
0fc4a33
remove commented-out code
37d8558
refactor code into InsufficientKeySize.qll
bfbb6db
clean up code
bcb506b
add placeholder qldocs
e0f0d55
condense code
2daa345
combine three configs into one
c61f23b
experiment with more code condensing
6eb58d8
remove dependence on typeFlag
47030df
remove commented-out 3 configs
0334470
remove commented out predicates that relied on typeFlag
da218fd
clean up code
2714c7f
update tests
5f39888
minor code restructure
383b8a8
update select statement to be closer to cpp's
ff557a2
add min key size predicates
dc8b62b
add support for AlgorithmParameterGenerator
4df0fbc
update tests
961e5c7
minor updates
e5982f1
minor updates
b7f3606
rename change note
345e4e0
remove unnecessary 'exists'
4c8e0a7
update qldoc of JavaSecurityKeyPairGenerator and JavaSecurityAlgoPara…
2ee23f0
update qldoc for AlgorithmParameterSpec
eb69b98
remove separators
8bc0a64
remove KeyGenInitMethodAccess class
09829d7
simplify instanceof usage
d569f93
update getAlgoSpec
c742a09
remove AlgoSpec class
1a12453
remove getNodeIntValue
1e80fa1
add modules
1bfdfc9
shorten class/predicate names
65f7474
simplify algorithm.matches
f40eefc
use CompileTimeConstantExpr instead of StringLiteral
910eebc
update change note
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
193 changes: 193 additions & 0 deletions
193
java/ql/lib/semmle/code/java/security/InsufficientKeySize.qll
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
/** Provides classes and predicates related to insufficient key sizes in Java. */ | ||
|
||
private import semmle.code.java.security.Encryption | ||
private import semmle.code.java.dataflow.DataFlow | ||
|
||
/** A source for an insufficient key size. */ | ||
abstract class InsufficientKeySizeSource extends DataFlow::Node { | ||
/** Holds if this source has the specified `state`. */ | ||
predicate hasState(DataFlow::FlowState state) { state instanceof DataFlow::FlowStateEmpty } | ||
} | ||
|
||
/** A sink for an insufficient key size. */ | ||
abstract class InsufficientKeySizeSink extends DataFlow::Node { | ||
/** Holds if this sink has the specified `state`. */ | ||
predicate hasState(DataFlow::FlowState state) { state instanceof DataFlow::FlowStateEmpty } | ||
} | ||
|
||
/** Provides models for asymmetric cryptography. */ | ||
private module Asymmetric { | ||
/** Provides models for non-elliptic-curve asymmetric cryptography. */ | ||
private module NonEllipticCurve { | ||
/** A source for an insufficient key size used in RSA, DSA, and DH algorithms. */ | ||
private class Source extends InsufficientKeySizeSource { | ||
Source() { this.asExpr().(IntegerLiteral).getIntValue() < getMinKeySize() } | ||
|
||
override predicate hasState(DataFlow::FlowState state) { state = getMinKeySize().toString() } | ||
} | ||
|
||
/** A sink for an insufficient key size used in RSA, DSA, and DH algorithms. */ | ||
private class Sink extends InsufficientKeySizeSink { | ||
Sink() { | ||
exists(KeyPairGenInit kpgInit, KeyPairGen kpg | | ||
kpg.getAlgoName().matches(["RSA", "DSA", "DH"]) and | ||
DataFlow::localExprFlow(kpg, kpgInit.getQualifier()) and | ||
this.asExpr() = kpgInit.getKeySizeArg() | ||
) | ||
or | ||
exists(Spec spec | this.asExpr() = spec.getKeySizeArg()) | ||
} | ||
|
||
override predicate hasState(DataFlow::FlowState state) { state = getMinKeySize().toString() } | ||
} | ||
|
||
/** Returns the minimum recommended key size for RSA, DSA, and DH algorithms. */ | ||
private int getMinKeySize() { result = 2048 } | ||
|
||
/** An instance of an RSA, DSA, or DH algorithm specification. */ | ||
private class Spec extends ClassInstanceExpr { | ||
Spec() { | ||
this.getConstructedType() instanceof RsaKeyGenParameterSpec or | ||
this.getConstructedType() instanceof DsaGenParameterSpec or | ||
this.getConstructedType() instanceof DhGenParameterSpec | ||
} | ||
|
||
/** Gets the `keysize` argument of this instance. */ | ||
Argument getKeySizeArg() { result = this.getArgument(0) } | ||
} | ||
} | ||
|
||
/** Provides models for elliptic-curve asymmetric cryptography. */ | ||
private module EllipticCurve { | ||
/** A source for an insufficient key size used in elliptic curve (EC) algorithms. */ | ||
private class Source extends InsufficientKeySizeSource { | ||
Source() { | ||
this.asExpr().(IntegerLiteral).getIntValue() < getMinKeySize() | ||
or | ||
// the below is needed for cases when the key size is embedded in the curve name | ||
getKeySize(this.asExpr().(StringLiteral).getValue()) < getMinKeySize() | ||
} | ||
|
||
override predicate hasState(DataFlow::FlowState state) { state = getMinKeySize().toString() } | ||
} | ||
|
||
/** A sink for an insufficient key size used in elliptic curve (EC) algorithms. */ | ||
private class Sink extends InsufficientKeySizeSink { | ||
Sink() { | ||
exists(KeyPairGenInit kpgInit, KeyPairGen kpg | | ||
kpg.getAlgoName().matches("EC%") and | ||
DataFlow::localExprFlow(kpg, kpgInit.getQualifier()) and | ||
this.asExpr() = kpgInit.getKeySizeArg() | ||
) | ||
or | ||
exists(Spec s | this.asExpr() = s.getKeySizeArg()) | ||
} | ||
|
||
override predicate hasState(DataFlow::FlowState state) { state = getMinKeySize().toString() } | ||
} | ||
|
||
/** Returns the minimum recommended key size for elliptic curve (EC) algorithms. */ | ||
private int getMinKeySize() { result = 256 } | ||
|
||
/** Returns the key size from an EC algorithm's curve name string */ | ||
bindingset[algorithm] | ||
private int getKeySize(string algorithm) { | ||
algorithm.matches("sec%") and // specification such as "secp256r1" | ||
result = algorithm.regexpCapture("sec[p|t](\\d+)[a-zA-Z].*", 1).toInt() | ||
or | ||
algorithm.matches("X9.62%") and // specification such as "X9.62 prime192v2" | ||
result = algorithm.regexpCapture("X9\\.62 .*[a-zA-Z](\\d+)[a-zA-Z].*", 1).toInt() | ||
or | ||
algorithm.matches(["prime%", "c2tnb%"]) and // specification such as "prime192v2" | ||
result = algorithm.regexpCapture(".*[a-zA-Z](\\d+)[a-zA-Z].*", 1).toInt() | ||
} | ||
|
||
/** An instance of an elliptic curve (EC) algorithm specification. */ | ||
private class Spec extends ClassInstanceExpr { | ||
Spec() { this.getConstructedType() instanceof EcGenParameterSpec } | ||
|
||
/** Gets the `keysize` argument of this instance. */ | ||
Argument getKeySizeArg() { result = this.getArgument(0) } | ||
} | ||
} | ||
|
||
/** | ||
* A call to the `initialize` method declared in `java.security.KeyPairGenerator` | ||
* or to the `init` method declared in `java.security.AlgorithmParameterGenerator`. | ||
*/ | ||
private class KeyPairGenInit extends MethodAccess { | ||
KeyPairGenInit() { | ||
this.getMethod() instanceof KeyPairGeneratorInitMethod or | ||
this.getMethod() instanceof AlgoParamGeneratorInitMethod | ||
} | ||
|
||
/** Gets the `keysize` argument of this call. */ | ||
Argument getKeySizeArg() { result = this.getArgument(0) } | ||
} | ||
|
||
/** | ||
* An instance of a `java.security.KeyPairGenerator` | ||
* or of a `java.security.AlgorithmParameterGenerator`. | ||
*/ | ||
private class KeyPairGen extends GeneratorAlgoSpec { | ||
KeyPairGen() { | ||
this instanceof JavaSecurityKeyPairGenerator or | ||
this instanceof JavaSecurityAlgoParamGenerator | ||
} | ||
|
||
override Expr getAlgoSpec() { | ||
result = | ||
[ | ||
this.(JavaSecurityKeyPairGenerator).getAlgoSpec(), | ||
this.(JavaSecurityAlgoParamGenerator).getAlgoSpec() | ||
] | ||
} | ||
} | ||
} | ||
|
||
/** Provides models for symmetric cryptography. */ | ||
private module Symmetric { | ||
/** A source for an insufficient key size used in AES algorithms. */ | ||
private class Source extends InsufficientKeySizeSource { | ||
Source() { this.asExpr().(IntegerLiteral).getIntValue() < getMinKeySize() } | ||
|
||
override predicate hasState(DataFlow::FlowState state) { state = getMinKeySize().toString() } | ||
} | ||
|
||
/** A sink for an insufficient key size used in AES algorithms. */ | ||
private class Sink extends InsufficientKeySizeSink { | ||
Sink() { | ||
exists(KeyGenInit kgInit, KeyGen kg | | ||
kg.getAlgoName() = "AES" and | ||
DataFlow::localExprFlow(kg, kgInit.getQualifier()) and | ||
this.asExpr() = kgInit.getKeySizeArg() | ||
) | ||
} | ||
|
||
override predicate hasState(DataFlow::FlowState state) { state = getMinKeySize().toString() } | ||
} | ||
|
||
/** Returns the minimum recommended key size for AES algorithms. */ | ||
private int getMinKeySize() { result = 128 } | ||
|
||
/** A call to the `init` method declared in `javax.crypto.KeyGenerator`. */ | ||
private class KeyGenInit extends MethodAccess { | ||
KeyGenInit() { this.getMethod() instanceof KeyGeneratorInitMethod } | ||
|
||
/** Gets the `keysize` argument of this call. */ | ||
Argument getKeySizeArg() { result = this.getArgument(0) } | ||
} | ||
|
||
/** An instance of a `javax.crypto.KeyGenerator`. */ | ||
private class KeyGen extends GeneratorAlgoSpec instanceof JavaxCryptoKeyGenerator { | ||
override Expr getAlgoSpec() { result = JavaxCryptoKeyGenerator.super.getAlgoSpec() } | ||
} | ||
} | ||
|
||
/** An instance of a generator that specifies an encryption algorithm. */ | ||
abstract private class GeneratorAlgoSpec extends CryptoAlgoSpec { | ||
/** Returns an uppercase string representing the algorithm name specified by this generator object. */ | ||
string getAlgoName() { | ||
result = this.getAlgoSpec().(CompileTimeConstantExpr).getStringValue().toUpperCase() | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
java/ql/lib/semmle/code/java/security/InsufficientKeySizeQuery.qll
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/** Provides data flow configurations to be used in queries related to insufficient key sizes. */ | ||
|
||
import semmle.code.java.dataflow.DataFlow | ||
import semmle.code.java.security.InsufficientKeySize | ||
|
||
/** A data flow configuration for tracking key sizes used in cryptographic algorithms. */ | ||
class KeySizeConfiguration extends DataFlow::Configuration { | ||
KeySizeConfiguration() { this = "KeySizeConfiguration" } | ||
|
||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { | ||
source.(InsufficientKeySizeSource).hasState(state) | ||
} | ||
|
||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { | ||
sink.(InsufficientKeySizeSink).hasState(state) | ||
} | ||
} |
55 changes: 55 additions & 0 deletions
55
java/ql/src/Security/CWE/CWE-326/InsufficientKeySize.qhelp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
<!DOCTYPE qhelp PUBLIC | ||
"-//Semmle//qhelp//EN" | ||
"qhelp.dtd"> | ||
<qhelp> | ||
|
||
<overview> | ||
<p>Modern encryption relies on the computational infeasibility of breaking a cipher and decoding its | ||
message without the key. As computational power increases, the ability to break ciphers grows, and key | ||
sizes need to become larger as a result. Cryptographic algorithms that use too small of a key size are | ||
vulnerable to brute force attacks, which can reveal sensitive data.</p> | ||
</overview> | ||
|
||
<recommendation> | ||
<p>Use a key of the recommended size or larger. The key size should be at least 128 bits for AES encryption, | ||
256 bits for elliptic-curve cryptography (ECC), and 2048 bits for RSA, DSA, or DH encryption.</p> | ||
</recommendation> | ||
|
||
<example> | ||
|
||
<p> | ||
The following code uses cryptographic algorithms with insufficient key sizes. | ||
</p> | ||
|
||
<sample src="InsufficientKeySizeBad.java" /> | ||
|
||
<p> | ||
To fix the code, change the key sizes to be the recommended size or | ||
larger for each algorithm. | ||
</p> | ||
|
||
</example> | ||
|
||
<references> | ||
<li> | ||
Wikipedia: | ||
<a href="http://en.wikipedia.org/wiki/Key_size">Key size</a>. | ||
</li> | ||
<li> | ||
Wikipedia: <a href="https://en.wikipedia.org/wiki/Strong_cryptography">Strong cryptography</a>. | ||
</li> | ||
<li> | ||
OWASP: <a href="https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#algorithms"> | ||
Cryptographic Storage Cheat Sheet</a>. | ||
</li> | ||
<li> | ||
OWASP: <a href="https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/09-Testing_for_Weak_Cryptography/04-Testing_for_Weak_Encryption"> | ||
Testing for Weak Encryption</a>. | ||
</li> | ||
<li> | ||
NIST: | ||
<a href="https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf"> | ||
Transitioning the Use of Cryptographic Algorithms and Key Lengths</a>. | ||
</li> | ||
</references> | ||
</qhelp> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/** | ||
* @name Use of a cryptographic algorithm with insufficient key size | ||
* @description Using cryptographic algorithms with too small a key size can | ||
* allow an attacker to compromise security. | ||
jcogs33 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* @kind path-problem | ||
* @problem.severity warning | ||
* @security-severity 7.5 | ||
* @precision high | ||
* @id java/insufficient-key-size | ||
* @tags security | ||
* external/cwe/cwe-326 | ||
*/ | ||
|
||
import java | ||
import semmle.code.java.security.InsufficientKeySizeQuery | ||
import DataFlow::PathGraph | ||
|
||
from DataFlow::PathNode source, DataFlow::PathNode sink, KeySizeConfiguration cfg | ||
where cfg.hasFlowPath(source, sink) | ||
select sink.getNode(), source, sink, | ||
"This $@ is less than the recommended key size of " + source.getState() + " bits.", | ||
source.getNode(), "key size" |
15 changes: 15 additions & 0 deletions
15
java/ql/src/Security/CWE/CWE-326/InsufficientKeySizeBad.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
KeyPairGenerator keyPairGen1 = KeyPairGenerator.getInstance("RSA"); | ||
keyPairGen1.initialize(1024); // BAD: Key size is less than 2048 | ||
|
||
KeyPairGenerator keyPairGen2 = KeyPairGenerator.getInstance("DSA"); | ||
keyPairGen2.initialize(1024); // BAD: Key size is less than 2048 | ||
|
||
KeyPairGenerator keyPairGen3 = KeyPairGenerator.getInstance("DH"); | ||
keyPairGen3.initialize(1024); // BAD: Key size is less than 2048 | ||
|
||
KeyPairGenerator keyPairGen4 = KeyPairGenerator.getInstance("EC"); | ||
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp112r1"); // BAD: Key size is less than 256 | ||
keyPairGen4.initialize(ecSpec); | ||
|
||
KeyGenerator keyGen = KeyGenerator.getInstance("AES"); | ||
keyGen.init(64); // BAD: Key size is less than 128 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
--- | ||
category: newQuery | ||
--- | ||
* The query `java/insufficient-key-size` has been promoted from experimental to the main query pack. Its results will now appear by default. This query was originally [submitted as an experimental query by @luchua-bc](https://github.com/github/codeql/pull/4926). |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.