mirror of
https://github.com/github/codeql.git
synced 2026-04-28 02:05:14 +02:00
Merge pull request #10785 from jcogs33/insuff-key-size-globalflow-keysize
Java: Promote insufficient key size query from experimental
This commit is contained in:
@@ -88,6 +88,22 @@ class KeyPairGenerator extends RefType {
|
||||
KeyPairGenerator() { this.hasQualifiedName("java.security", "KeyPairGenerator") }
|
||||
}
|
||||
|
||||
/** The `init` method declared in `javax.crypto.KeyGenerator`. */
|
||||
class KeyGeneratorInitMethod extends Method {
|
||||
KeyGeneratorInitMethod() {
|
||||
this.getDeclaringType() instanceof KeyGenerator and
|
||||
this.hasName("init")
|
||||
}
|
||||
}
|
||||
|
||||
/** The `initialize` method declared in `java.security.KeyPairGenerator`. */
|
||||
class KeyPairGeneratorInitMethod extends Method {
|
||||
KeyPairGeneratorInitMethod() {
|
||||
this.getDeclaringType() instanceof KeyPairGenerator and
|
||||
this.hasName("initialize")
|
||||
}
|
||||
}
|
||||
|
||||
/** The `verify` method of the class `javax.net.ssl.HostnameVerifier`. */
|
||||
class HostnameVerifierVerify extends Method {
|
||||
HostnameVerifierVerify() {
|
||||
@@ -367,8 +383,8 @@ class JavaSecuritySignature extends JavaSecurityAlgoSpec {
|
||||
override Expr getAlgoSpec() { result = this.(ConstructorCall).getArgument(0) }
|
||||
}
|
||||
|
||||
/** A method call to the Java class `java.security.KeyPairGenerator`. */
|
||||
class JavaSecurityKeyPairGenerator extends JavaxCryptoAlgoSpec {
|
||||
/** A call to the `getInstance` method declared in `java.security.KeyPairGenerator`. */
|
||||
class JavaSecurityKeyPairGenerator extends JavaSecurityAlgoSpec {
|
||||
JavaSecurityKeyPairGenerator() {
|
||||
exists(Method m | m.getAReference() = this |
|
||||
m.getDeclaringType() instanceof KeyPairGenerator and
|
||||
@@ -378,3 +394,53 @@ class JavaSecurityKeyPairGenerator extends JavaxCryptoAlgoSpec {
|
||||
|
||||
override Expr getAlgoSpec() { result = this.(MethodAccess).getArgument(0) }
|
||||
}
|
||||
|
||||
/** The Java class `java.security.AlgorithmParameterGenerator`. */
|
||||
class AlgorithmParameterGenerator extends RefType {
|
||||
AlgorithmParameterGenerator() {
|
||||
this.hasQualifiedName("java.security", "AlgorithmParameterGenerator")
|
||||
}
|
||||
}
|
||||
|
||||
/** The `init` method declared in `java.security.AlgorithmParameterGenerator`. */
|
||||
class AlgoParamGeneratorInitMethod extends Method {
|
||||
AlgoParamGeneratorInitMethod() {
|
||||
this.getDeclaringType() instanceof AlgorithmParameterGenerator and
|
||||
this.hasName("init")
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to the `getInstance` method declared in `java.security.AlgorithmParameterGenerator`. */
|
||||
class JavaSecurityAlgoParamGenerator extends JavaSecurityAlgoSpec {
|
||||
JavaSecurityAlgoParamGenerator() {
|
||||
exists(Method m | m.getAReference() = this |
|
||||
m.getDeclaringType() instanceof AlgorithmParameterGenerator and
|
||||
m.getName() = "getInstance"
|
||||
)
|
||||
}
|
||||
|
||||
override Expr getAlgoSpec() { result = this.(MethodAccess).getArgument(0) }
|
||||
}
|
||||
|
||||
/** An implementation of the `java.security.spec.AlgorithmParameterSpec` interface. */
|
||||
abstract class AlgorithmParameterSpec extends RefType { }
|
||||
|
||||
/** The Java class `java.security.spec.ECGenParameterSpec`. */
|
||||
class EcGenParameterSpec extends AlgorithmParameterSpec {
|
||||
EcGenParameterSpec() { this.hasQualifiedName("java.security.spec", "ECGenParameterSpec") }
|
||||
}
|
||||
|
||||
/** The Java class `java.security.spec.RSAKeyGenParameterSpec`. */
|
||||
class RsaKeyGenParameterSpec extends AlgorithmParameterSpec {
|
||||
RsaKeyGenParameterSpec() { this.hasQualifiedName("java.security.spec", "RSAKeyGenParameterSpec") }
|
||||
}
|
||||
|
||||
/** The Java class `java.security.spec.DSAGenParameterSpec`. */
|
||||
class DsaGenParameterSpec extends AlgorithmParameterSpec {
|
||||
DsaGenParameterSpec() { this.hasQualifiedName("java.security.spec", "DSAGenParameterSpec") }
|
||||
}
|
||||
|
||||
/** The Java class `javax.crypto.spec.DHGenParameterSpec`. */
|
||||
class DhGenParameterSpec extends AlgorithmParameterSpec {
|
||||
DhGenParameterSpec() { this.hasQualifiedName("javax.crypto.spec", "DHGenParameterSpec") }
|
||||
}
|
||||
|
||||
193
java/ql/lib/semmle/code/java/security/InsufficientKeySize.qll
Normal file
193
java/ql/lib/semmle/code/java/security/InsufficientKeySize.qll
Normal file
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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
java/ql/src/Security/CWE/CWE-326/InsufficientKeySize.qhelp
Normal file
55
java/ql/src/Security/CWE/CWE-326/InsufficientKeySize.qhelp
Normal file
@@ -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>
|
||||
22
java/ql/src/Security/CWE/CWE-326/InsufficientKeySize.ql
Normal file
22
java/ql/src/Security/CWE/CWE-326/InsufficientKeySize.ql
Normal file
@@ -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.
|
||||
* @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
java/ql/src/Security/CWE/CWE-326/InsufficientKeySizeBad.java
Normal file
15
java/ql/src/Security/CWE/CWE-326/InsufficientKeySizeBad.java
Normal file
@@ -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
|
||||
@@ -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).
|
||||
@@ -1,37 +0,0 @@
|
||||
public class InsufficientKeySize {
|
||||
public void CryptoMethod() {
|
||||
KeyGenerator keyGen1 = KeyGenerator.getInstance("AES");
|
||||
// BAD: Key size is less than 128
|
||||
keyGen1.init(64);
|
||||
|
||||
KeyGenerator keyGen2 = KeyGenerator.getInstance("AES");
|
||||
// GOOD: Key size is no less than 128
|
||||
keyGen2.init(128);
|
||||
|
||||
KeyPairGenerator keyPairGen1 = KeyPairGenerator.getInstance("RSA");
|
||||
// BAD: Key size is less than 2048
|
||||
keyPairGen1.initialize(1024);
|
||||
|
||||
KeyPairGenerator keyPairGen2 = KeyPairGenerator.getInstance("RSA");
|
||||
// GOOD: Key size is no less than 2048
|
||||
keyPairGen2.initialize(2048);
|
||||
|
||||
KeyPairGenerator keyPairGen3 = KeyPairGenerator.getInstance("DSA");
|
||||
// BAD: Key size is less than 2048
|
||||
keyPairGen3.initialize(1024);
|
||||
|
||||
KeyPairGenerator keyPairGen4 = KeyPairGenerator.getInstance("DSA");
|
||||
// GOOD: Key size is no less than 2048
|
||||
keyPairGen4.initialize(2048);
|
||||
|
||||
KeyPairGenerator keyPairGen5 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is less than 256
|
||||
ECGenParameterSpec ecSpec1 = new ECGenParameterSpec("secp112r1");
|
||||
keyPairGen5.initialize(ecSpec1);
|
||||
|
||||
KeyPairGenerator keyPairGen6 = KeyPairGenerator.getInstance("EC");
|
||||
// GOOD: Key size is no less than 256
|
||||
ECGenParameterSpec ecSpec2 = new ECGenParameterSpec("secp256r1");
|
||||
keyPairGen6.initialize(ecSpec2);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>This rule finds uses of encryption algorithms with too small a key size. Encryption algorithms
|
||||
are vulnerable to brute force attack when too small a key size is used.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>The key should be at least 2048 bits long when using RSA and DSA encryption, 256 bits long when using EC encryption, and 128 bits long when using
|
||||
symmetric encryption.</p>
|
||||
</recommendation>
|
||||
|
||||
<references>
|
||||
|
||||
<li>
|
||||
Wikipedia.
|
||||
<a href="http://en.wikipedia.org/wiki/Key_size">Key size</a>
|
||||
</li>
|
||||
<li>
|
||||
SonarSource.
|
||||
<a href="https://rules.sonarsource.com/java/type/Vulnerability/RSPEC-4426">Cryptographic keys should be robust</a>
|
||||
</li>
|
||||
<li>
|
||||
CWE.
|
||||
<a href="https://cwe.mitre.org/data/definitions/326.html">CWE-326: Inadequate Encryption Strength</a>
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -1,153 +0,0 @@
|
||||
/**
|
||||
* @name Weak encryption: Insufficient key size
|
||||
* @description Finds uses of encryption algorithms with too small a key size
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/insufficient-key-size
|
||||
* @tags security
|
||||
* external/cwe/cwe-326
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.Encryption
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
|
||||
/** The Java class `java.security.spec.ECGenParameterSpec`. */
|
||||
class ECGenParameterSpec extends RefType {
|
||||
ECGenParameterSpec() { this.hasQualifiedName("java.security.spec", "ECGenParameterSpec") }
|
||||
}
|
||||
|
||||
/** The `init` method declared in `javax.crypto.KeyGenerator`. */
|
||||
class KeyGeneratorInitMethod extends Method {
|
||||
KeyGeneratorInitMethod() {
|
||||
this.getDeclaringType() instanceof KeyGenerator and
|
||||
this.hasName("init")
|
||||
}
|
||||
}
|
||||
|
||||
/** The `initialize` method declared in `java.security.KeyPairGenerator`. */
|
||||
class KeyPairGeneratorInitMethod extends Method {
|
||||
KeyPairGeneratorInitMethod() {
|
||||
this.getDeclaringType() instanceof KeyPairGenerator and
|
||||
this.hasName("initialize")
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the key size in the EC algorithm string */
|
||||
bindingset[algorithm]
|
||||
int getECKeySize(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%") or algorithm.matches("c2tnb%")) and //specification such as "prime192v2"
|
||||
result = algorithm.regexpCapture(".*[a-zA-Z](\\d+)[a-zA-Z].*", 1).toInt()
|
||||
}
|
||||
|
||||
/** Taint configuration tracking flow from a key generator to a `init` method call. */
|
||||
class KeyGeneratorInitConfiguration extends TaintTracking::Configuration {
|
||||
KeyGeneratorInitConfiguration() { this = "KeyGeneratorInitConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr() instanceof JavaxCryptoKeyGenerator
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof KeyGeneratorInitMethod and
|
||||
sink.asExpr() = ma.getQualifier()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Taint configuration tracking flow from a keypair generator to a `initialize` method call. */
|
||||
class KeyPairGeneratorInitConfiguration extends TaintTracking::Configuration {
|
||||
KeyPairGeneratorInitConfiguration() { this = "KeyPairGeneratorInitConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr() instanceof JavaSecurityKeyPairGenerator
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof KeyPairGeneratorInitMethod and
|
||||
sink.asExpr() = ma.getQualifier()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if a symmetric `KeyGenerator` implementing encryption algorithm `type` and initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */
|
||||
bindingset[type]
|
||||
predicate hasShortSymmetricKey(MethodAccess ma, string msg, string type) {
|
||||
ma.getMethod() instanceof KeyGeneratorInitMethod and
|
||||
exists(
|
||||
JavaxCryptoKeyGenerator jcg, KeyGeneratorInitConfiguration cc, DataFlow::PathNode source,
|
||||
DataFlow::PathNode dest
|
||||
|
|
||||
jcg.getAlgoSpec().(StringLiteral).getValue() = type and
|
||||
source.getNode().asExpr() = jcg and
|
||||
dest.getNode().asExpr() = ma.getQualifier() and
|
||||
cc.hasFlowPath(source, dest)
|
||||
) and
|
||||
ma.getArgument(0).(IntegerLiteral).getIntValue() < 128 and
|
||||
msg = "Key size should be at least 128 bits for " + type + " encryption."
|
||||
}
|
||||
|
||||
/** Holds if an AES `KeyGenerator` initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */
|
||||
predicate hasShortAESKey(MethodAccess ma, string msg) { hasShortSymmetricKey(ma, msg, "AES") }
|
||||
|
||||
/** Holds if an asymmetric `KeyPairGenerator` implementing encryption algorithm `type` and initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */
|
||||
bindingset[type]
|
||||
predicate hasShortAsymmetricKeyPair(MethodAccess ma, string msg, string type) {
|
||||
ma.getMethod() instanceof KeyPairGeneratorInitMethod and
|
||||
exists(
|
||||
JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorInitConfiguration kc,
|
||||
DataFlow::PathNode source, DataFlow::PathNode dest
|
||||
|
|
||||
jpg.getAlgoSpec().(StringLiteral).getValue().toUpperCase() = type and
|
||||
source.getNode().asExpr() = jpg and
|
||||
dest.getNode().asExpr() = ma.getQualifier() and
|
||||
kc.hasFlowPath(source, dest)
|
||||
) and
|
||||
ma.getArgument(0).(IntegerLiteral).getIntValue() < 2048 and
|
||||
msg = "Key size should be at least 2048 bits for " + type + " encryption."
|
||||
}
|
||||
|
||||
/** Holds if a DSA `KeyPairGenerator` initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */
|
||||
predicate hasShortDsaKeyPair(MethodAccess ma, string msg) {
|
||||
hasShortAsymmetricKeyPair(ma, msg, "DSA") or hasShortAsymmetricKeyPair(ma, msg, "DH")
|
||||
}
|
||||
|
||||
/** Holds if a RSA `KeyPairGenerator` initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */
|
||||
predicate hasShortRsaKeyPair(MethodAccess ma, string msg) {
|
||||
hasShortAsymmetricKeyPair(ma, msg, "RSA")
|
||||
}
|
||||
|
||||
/** Holds if an EC `KeyPairGenerator` initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */
|
||||
predicate hasShortECKeyPair(MethodAccess ma, string msg) {
|
||||
ma.getMethod() instanceof KeyPairGeneratorInitMethod and
|
||||
exists(
|
||||
JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorInitConfiguration kc,
|
||||
DataFlow::PathNode source, DataFlow::PathNode dest, ClassInstanceExpr cie
|
||||
|
|
||||
jpg.getAlgoSpec().(StringLiteral).getValue().matches("EC%") and // ECC variants such as ECDH and ECDSA
|
||||
source.getNode().asExpr() = jpg and
|
||||
dest.getNode().asExpr() = ma.getQualifier() and
|
||||
kc.hasFlowPath(source, dest) and
|
||||
DataFlow::localExprFlow(cie, ma.getArgument(0)) and
|
||||
ma.getArgument(0).getType() instanceof ECGenParameterSpec and
|
||||
getECKeySize(cie.getArgument(0).(StringLiteral).getValue()) < 256
|
||||
) and
|
||||
msg = "Key size should be at least 256 bits for EC encryption."
|
||||
}
|
||||
|
||||
from Expr e, string msg
|
||||
where
|
||||
hasShortAESKey(e, msg) or
|
||||
hasShortDsaKeyPair(e, msg) or
|
||||
hasShortRsaKeyPair(e, msg) or
|
||||
hasShortECKeyPair(e, msg)
|
||||
select e, msg
|
||||
@@ -1,11 +0,0 @@
|
||||
| InsufficientKeySize.java:9:9:9:24 | init(...) | Key size should be at least 128 bits for AES encryption. |
|
||||
| InsufficientKeySize.java:17:9:17:36 | initialize(...) | Key size should be at least 2048 bits for RSA encryption. |
|
||||
| InsufficientKeySize.java:25:9:25:36 | initialize(...) | Key size should be at least 2048 bits for DSA encryption. |
|
||||
| InsufficientKeySize.java:34:9:34:39 | initialize(...) | Key size should be at least 256 bits for EC encryption. |
|
||||
| InsufficientKeySize.java:38:9:38:67 | initialize(...) | Key size should be at least 256 bits for EC encryption. |
|
||||
| InsufficientKeySize.java:48:9:48:39 | initialize(...) | Key size should be at least 256 bits for EC encryption. |
|
||||
| InsufficientKeySize.java:53:9:53:39 | initialize(...) | Key size should be at least 256 bits for EC encryption. |
|
||||
| InsufficientKeySize.java:58:9:58:40 | initialize(...) | Key size should be at least 256 bits for EC encryption. |
|
||||
| InsufficientKeySize.java:68:9:68:40 | initialize(...) | Key size should be at least 256 bits for EC encryption. |
|
||||
| InsufficientKeySize.java:78:9:78:40 | initialize(...) | Key size should be at least 256 bits for EC encryption. |
|
||||
| InsufficientKeySize.java:87:9:87:37 | initialize(...) | Key size should be at least 2048 bits for DH encryption. |
|
||||
@@ -1,93 +0,0 @@
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.spec.ECGenParameterSpec;
|
||||
import javax.crypto.KeyGenerator;
|
||||
|
||||
public class InsufficientKeySize {
|
||||
public void CryptoMethod() throws java.security.NoSuchAlgorithmException, java.security.InvalidAlgorithmParameterException {
|
||||
KeyGenerator keyGen1 = KeyGenerator.getInstance("AES");
|
||||
// BAD: Key size is less than 128
|
||||
keyGen1.init(64);
|
||||
|
||||
KeyGenerator keyGen2 = KeyGenerator.getInstance("AES");
|
||||
// GOOD: Key size is no less than 128
|
||||
keyGen2.init(128);
|
||||
|
||||
KeyPairGenerator keyPairGen1 = KeyPairGenerator.getInstance("RSA");
|
||||
// BAD: Key size is less than 2048
|
||||
keyPairGen1.initialize(1024);
|
||||
|
||||
KeyPairGenerator keyPairGen2 = KeyPairGenerator.getInstance("RSA");
|
||||
// GOOD: Key size is no less than 2048
|
||||
keyPairGen2.initialize(2048);
|
||||
|
||||
KeyPairGenerator keyPairGen3 = KeyPairGenerator.getInstance("DSA");
|
||||
// BAD: Key size is less than 2048
|
||||
keyPairGen3.initialize(1024);
|
||||
|
||||
KeyPairGenerator keyPairGen4 = KeyPairGenerator.getInstance("DSA");
|
||||
// GOOD: Key size is no less than 2048
|
||||
keyPairGen4.initialize(2048);
|
||||
|
||||
KeyPairGenerator keyPairGen5 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is less than 256
|
||||
ECGenParameterSpec ecSpec1 = new ECGenParameterSpec("secp112r1");
|
||||
keyPairGen5.initialize(ecSpec1);
|
||||
|
||||
KeyPairGenerator keyPairGen6 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is less than 256
|
||||
keyPairGen6.initialize(new ECGenParameterSpec("secp112r1"));
|
||||
|
||||
KeyPairGenerator keyPairGen7 = KeyPairGenerator.getInstance("EC");
|
||||
// GOOD: Key size is no less than 256
|
||||
ECGenParameterSpec ecSpec2 = new ECGenParameterSpec("secp256r1");
|
||||
keyPairGen7.initialize(ecSpec2);
|
||||
|
||||
KeyPairGenerator keyPairGen8 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is less than 256
|
||||
ECGenParameterSpec ecSpec3 = new ECGenParameterSpec("X9.62 prime192v2");
|
||||
keyPairGen8.initialize(ecSpec3);
|
||||
|
||||
KeyPairGenerator keyPairGen9 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is less than 256
|
||||
ECGenParameterSpec ecSpec4 = new ECGenParameterSpec("X9.62 c2tnb191v3");
|
||||
keyPairGen9.initialize(ecSpec4);
|
||||
|
||||
KeyPairGenerator keyPairGen10 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is less than 256
|
||||
ECGenParameterSpec ecSpec5 = new ECGenParameterSpec("sect163k1");
|
||||
keyPairGen10.initialize(ecSpec5);
|
||||
|
||||
KeyPairGenerator keyPairGen11 = KeyPairGenerator.getInstance("EC");
|
||||
// GOOD: Key size is no less than 256
|
||||
ECGenParameterSpec ecSpec6 = new ECGenParameterSpec("X9.62 c2tnb359v1");
|
||||
keyPairGen11.initialize(ecSpec6);
|
||||
|
||||
KeyPairGenerator keyPairGen12 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is less than 256
|
||||
ECGenParameterSpec ecSpec7 = new ECGenParameterSpec("prime192v2");
|
||||
keyPairGen12.initialize(ecSpec7);
|
||||
|
||||
KeyPairGenerator keyPairGen13 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is no less than 256
|
||||
ECGenParameterSpec ecSpec8 = new ECGenParameterSpec("prime256v1");
|
||||
keyPairGen13.initialize(ecSpec8);
|
||||
|
||||
KeyPairGenerator keyPairGen14 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is less than 256
|
||||
ECGenParameterSpec ecSpec9 = new ECGenParameterSpec("c2tnb191v1");
|
||||
keyPairGen14.initialize(ecSpec9);
|
||||
|
||||
KeyPairGenerator keyPairGen15 = KeyPairGenerator.getInstance("EC");
|
||||
// BAD: Key size is no less than 256
|
||||
ECGenParameterSpec ecSpec10 = new ECGenParameterSpec("c2tnb431r1");
|
||||
keyPairGen15.initialize(ecSpec10);
|
||||
|
||||
KeyPairGenerator keyPairGen16 = KeyPairGenerator.getInstance("dh");
|
||||
// BAD: Key size is less than 2048
|
||||
keyPairGen16.initialize(1024);
|
||||
|
||||
KeyPairGenerator keyPairGen17 = KeyPairGenerator.getInstance("DH");
|
||||
// GOOD: Key size is no less than 2048
|
||||
keyPairGen17.initialize(2048);
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Security/CWE/CWE-326/InsufficientKeySize.ql
|
||||
@@ -0,0 +1,256 @@
|
||||
import javax.crypto.KeyGenerator;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.AlgorithmParameterGenerator;
|
||||
import java.security.spec.ECGenParameterSpec;
|
||||
import java.security.spec.RSAKeyGenParameterSpec;
|
||||
import java.security.spec.DSAGenParameterSpec;
|
||||
import javax.crypto.spec.DHGenParameterSpec;
|
||||
|
||||
|
||||
public class InsufficientKeySizeTest {
|
||||
public void keySizeTesting() throws java.security.NoSuchAlgorithmException, java.security.InvalidAlgorithmParameterException {
|
||||
|
||||
/* AES (Symmetric): minimum recommended key size is 128 */
|
||||
{
|
||||
/* Test with keysize as int */
|
||||
KeyGenerator keyGen1 = KeyGenerator.getInstance("AES");
|
||||
keyGen1.init(64); // $ hasInsufficientKeySize
|
||||
|
||||
KeyGenerator keyGen2 = KeyGenerator.getInstance("AES");
|
||||
keyGen2.init(128); // Safe: Key size is no less than 128
|
||||
|
||||
/* Test with local variable as keysize */
|
||||
final int size1 = 64; // compile-time constant
|
||||
int size2 = 64; // not a compile-time constant
|
||||
|
||||
KeyGenerator keyGen3 = KeyGenerator.getInstance("AES");
|
||||
keyGen3.init(size1); // $ hasInsufficientKeySize
|
||||
|
||||
KeyGenerator keyGen4 = KeyGenerator.getInstance("AES");
|
||||
keyGen4.init(size2); // $ hasInsufficientKeySize
|
||||
|
||||
/* Test variables passed to another method */
|
||||
KeyGenerator keyGen5 = KeyGenerator.getInstance("AES"); // MISSING: test KeyGenerator variable as argument
|
||||
testSymmetricVariable(size2, keyGen5); // test with variable as key size
|
||||
testSymmetricInt(64); // test with int literal as key size
|
||||
|
||||
/* Test with variable as algo name argument in `getInstance` method. */
|
||||
final String algoName1 = "AES"; // compile-time constant
|
||||
KeyGenerator keyGen6 = KeyGenerator.getInstance(algoName1);
|
||||
keyGen6.init(64); // $ hasInsufficientKeySize
|
||||
|
||||
String algoName2 = "AES"; // not a compile-time constant
|
||||
KeyGenerator keyGen7 = KeyGenerator.getInstance(algoName2);
|
||||
keyGen7.init(64); // $ MISSING: hasInsufficientKeySize
|
||||
}
|
||||
|
||||
// RSA (Asymmetric): minimum recommended key size is 2048
|
||||
{
|
||||
/* Test with keysize as int */
|
||||
KeyPairGenerator keyPairGen1 = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGen1.initialize(1024); // $ hasInsufficientKeySize
|
||||
|
||||
KeyPairGenerator keyPairGen2 = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGen2.initialize(2048); // Safe: Key size is no less than 2048
|
||||
|
||||
/* Test spec */
|
||||
KeyPairGenerator keyPairGen3 = KeyPairGenerator.getInstance("RSA");
|
||||
RSAKeyGenParameterSpec rsaSpec = new RSAKeyGenParameterSpec(1024, null); // $ hasInsufficientKeySize
|
||||
keyPairGen3.initialize(rsaSpec);
|
||||
|
||||
KeyPairGenerator keyPairGen4 = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGen4.initialize(new RSAKeyGenParameterSpec(1024, null)); // $ hasInsufficientKeySize
|
||||
|
||||
/* Test with local variable as keysize */
|
||||
final int size1 = 1024; // compile-time constant
|
||||
int size2 = 1024; // not a compile-time constant
|
||||
|
||||
KeyPairGenerator keyPairGen5 = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGen5.initialize(size1); // $ hasInsufficientKeySize
|
||||
|
||||
KeyPairGenerator keyPairGen6 = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGen6.initialize(size2); // $ hasInsufficientKeySize
|
||||
|
||||
/* Test variables passed to another method */
|
||||
KeyPairGenerator keyPairGen7 = KeyPairGenerator.getInstance("RSA"); // MISSING: test KeyGenerator variable as argument
|
||||
testAsymmetricNonEcVariable(size2, keyPairGen7); // test with variable as key size
|
||||
testAsymmetricNonEcInt(1024); // test with int literal as key size
|
||||
|
||||
/* Test getting key size as return value of another method */
|
||||
KeyPairGenerator keyPairGen8 = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGen8.initialize(getRSAKeySize()); // $ hasInsufficientKeySize
|
||||
|
||||
/* Test with variable as algo name argument in `getInstance` method. */
|
||||
final String algoName1 = "RSA"; // compile-time constant
|
||||
KeyPairGenerator keyPairGen9 = KeyPairGenerator.getInstance(algoName1);
|
||||
keyPairGen9.initialize(1024); // $ hasInsufficientKeySize
|
||||
|
||||
String algoName2 = "RSA"; // not a compile-time constant
|
||||
KeyPairGenerator keyPairGen10 = KeyPairGenerator.getInstance(algoName2);
|
||||
keyPairGen10.initialize(1024); // $ MISSING: hasInsufficientKeySize
|
||||
}
|
||||
|
||||
// DSA (Asymmetric): minimum recommended key size is 2048
|
||||
{
|
||||
/* Test with keysize as int */
|
||||
KeyPairGenerator keyPairGen1 = KeyPairGenerator.getInstance("DSA");
|
||||
keyPairGen1.initialize(1024); // $ hasInsufficientKeySize
|
||||
|
||||
KeyPairGenerator keyPairGen2 = KeyPairGenerator.getInstance("DSA");
|
||||
keyPairGen2.initialize(2048); // Safe: Key size is no less than 2048
|
||||
|
||||
/* Test spec */
|
||||
KeyPairGenerator keyPairGen3 = KeyPairGenerator.getInstance("DSA");
|
||||
DSAGenParameterSpec dsaSpec = new DSAGenParameterSpec(1024, 0); // $ hasInsufficientKeySize
|
||||
keyPairGen3.initialize(dsaSpec);
|
||||
|
||||
KeyPairGenerator keyPairGen4 = KeyPairGenerator.getInstance("DSA");
|
||||
keyPairGen4.initialize(new DSAGenParameterSpec(1024, 0)); // $ hasInsufficientKeySize
|
||||
|
||||
/* Test `AlgorithmParameterGenerator` */
|
||||
AlgorithmParameterGenerator paramGen = AlgorithmParameterGenerator.getInstance("DSA");
|
||||
paramGen.init(1024); // $ hasInsufficientKeySize
|
||||
|
||||
/* Test with variable as algo name argument in `getInstance` method. */
|
||||
final String algoName1 = "DSA"; // compile-time constant
|
||||
AlgorithmParameterGenerator paramGen1 = AlgorithmParameterGenerator.getInstance(algoName1);
|
||||
paramGen1.init(1024); // $ hasInsufficientKeySize
|
||||
|
||||
String algoName2 = "DSA"; // not a compile-time constant
|
||||
AlgorithmParameterGenerator paramGen2 = AlgorithmParameterGenerator.getInstance(algoName2);
|
||||
paramGen2.init(1024); // $ MISSING: hasInsufficientKeySize
|
||||
}
|
||||
|
||||
// DH (Asymmetric): minimum recommended key size is 2048
|
||||
{
|
||||
/* Test with keysize as int */
|
||||
KeyPairGenerator keyPairGen1 = KeyPairGenerator.getInstance("dh");
|
||||
keyPairGen1.initialize(1024); // $ hasInsufficientKeySize
|
||||
|
||||
KeyPairGenerator keyPairGen2 = KeyPairGenerator.getInstance("DH");
|
||||
keyPairGen2.initialize(2048); // Safe: Key size is no less than 2048
|
||||
|
||||
/* Test spec */
|
||||
KeyPairGenerator keyPairGen3 = KeyPairGenerator.getInstance("DH");
|
||||
DHGenParameterSpec dhSpec = new DHGenParameterSpec(1024, 0); // $ hasInsufficientKeySize
|
||||
keyPairGen3.initialize(dhSpec);
|
||||
|
||||
KeyPairGenerator keyPairGen4 = KeyPairGenerator.getInstance("DH");
|
||||
keyPairGen4.initialize(new DHGenParameterSpec(1024, 0)); // $ hasInsufficientKeySize
|
||||
|
||||
/* Test `AlgorithmParameterGenerator` */
|
||||
AlgorithmParameterGenerator paramGen = AlgorithmParameterGenerator.getInstance("DH");
|
||||
paramGen.init(1024); // $ hasInsufficientKeySize
|
||||
}
|
||||
|
||||
// EC (Asymmetric): minimum recommended key size is 256
|
||||
{
|
||||
/* Test with keysize as int */
|
||||
KeyPairGenerator keyPairGen1 = KeyPairGenerator.getInstance("EC");
|
||||
keyPairGen1.initialize(128); // $ hasInsufficientKeySize
|
||||
|
||||
/* Test with keysize as curve name in spec */
|
||||
KeyPairGenerator keyPairGen2 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec1 = new ECGenParameterSpec("secp112r1"); // $ hasInsufficientKeySize
|
||||
keyPairGen2.initialize(ecSpec1);
|
||||
|
||||
KeyPairGenerator keyPairGen3 = KeyPairGenerator.getInstance("EC");
|
||||
keyPairGen3.initialize(new ECGenParameterSpec("secp112r1")); // $ hasInsufficientKeySize
|
||||
|
||||
KeyPairGenerator keyPairGen4 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec2 = new ECGenParameterSpec("secp256r1"); // Safe: Key size is no less than 256
|
||||
keyPairGen4.initialize(ecSpec2);
|
||||
|
||||
KeyPairGenerator keyPairGen5 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec3 = new ECGenParameterSpec("X9.62 prime192v2"); // $ hasInsufficientKeySize
|
||||
keyPairGen5.initialize(ecSpec3);
|
||||
|
||||
KeyPairGenerator keyPairGen6 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec4 = new ECGenParameterSpec("X9.62 c2tnb191v3"); // $ hasInsufficientKeySize
|
||||
keyPairGen6.initialize(ecSpec4);
|
||||
|
||||
KeyPairGenerator keyPairGen7 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec5 = new ECGenParameterSpec("sect163k1"); // $ hasInsufficientKeySize
|
||||
keyPairGen7.initialize(ecSpec5);
|
||||
|
||||
KeyPairGenerator keyPairGen8 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec6 = new ECGenParameterSpec("X9.62 c2tnb359v1"); // Safe: Key size is no less than 256
|
||||
keyPairGen8.initialize(ecSpec6);
|
||||
|
||||
KeyPairGenerator keyPairGen9 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec7 = new ECGenParameterSpec("prime192v2"); // $ hasInsufficientKeySize
|
||||
keyPairGen9.initialize(ecSpec7);
|
||||
|
||||
KeyPairGenerator keyPairGen10 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec8 = new ECGenParameterSpec("prime256v1"); // Safe: Key size is no less than 256
|
||||
keyPairGen10.initialize(ecSpec8);
|
||||
|
||||
KeyPairGenerator keyPairGen14 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec9 = new ECGenParameterSpec("c2tnb191v1"); // $ hasInsufficientKeySize
|
||||
keyPairGen14.initialize(ecSpec9);
|
||||
|
||||
KeyPairGenerator keyPairGen15 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec10 = new ECGenParameterSpec("c2tnb431r1");
|
||||
keyPairGen15.initialize(ecSpec10); // Safe: Key size is no less than 256
|
||||
|
||||
/* Test variables passed to another method */
|
||||
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp112r1"); // $ hasInsufficientKeySize
|
||||
testAsymmetricEcSpecVariable(ecSpec); // test spec as an argument
|
||||
int size = 128;
|
||||
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("EC"); // MISSING: test KeyGenerator variable as argument
|
||||
testAsymmetricEcIntVariable(size, keyPairGen); // test with variable as key size
|
||||
testAsymmetricEcIntLiteral(128); // test with int literal as key size
|
||||
|
||||
/* Test with variable as curve name argument in `ECGenParameterSpec` constructor. */
|
||||
final String curveName1 = "secp112r1"; // compile-time constant
|
||||
KeyPairGenerator keyPairGen16 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec11 = new ECGenParameterSpec(curveName1); // $ hasInsufficientKeySize
|
||||
keyPairGen16.initialize(ecSpec11);
|
||||
|
||||
String curveName2 = "secp112r1"; // not a compile-time constant
|
||||
KeyPairGenerator keyPairGen17 = KeyPairGenerator.getInstance("EC");
|
||||
ECGenParameterSpec ecSpec12 = new ECGenParameterSpec(curveName2); // $ hasInsufficientKeySize
|
||||
keyPairGen17.initialize(ecSpec12);
|
||||
}
|
||||
}
|
||||
|
||||
public static void testSymmetricVariable(int keySize, KeyGenerator kg) throws java.security.NoSuchAlgorithmException, java.security.InvalidAlgorithmParameterException {
|
||||
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
|
||||
keyGen.init(keySize); // $ hasInsufficientKeySize
|
||||
kg.init(64); // $ MISSING: hasInsufficientKeySize
|
||||
}
|
||||
|
||||
public static void testSymmetricInt(int keySize) throws java.security.NoSuchAlgorithmException, java.security.InvalidAlgorithmParameterException {
|
||||
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
|
||||
keyGen.init(keySize); // $ hasInsufficientKeySize
|
||||
}
|
||||
|
||||
public static void testAsymmetricNonEcVariable(int keySize, KeyPairGenerator kpg) throws java.security.NoSuchAlgorithmException, java.security.InvalidAlgorithmParameterException {
|
||||
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGen.initialize(keySize); // $ hasInsufficientKeySize
|
||||
kpg.initialize(1024); // $ MISSING: hasInsufficientKeySize
|
||||
}
|
||||
|
||||
public static void testAsymmetricNonEcInt(int keySize) throws java.security.NoSuchAlgorithmException, java.security.InvalidAlgorithmParameterException {
|
||||
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGen.initialize(keySize); // $ hasInsufficientKeySize
|
||||
}
|
||||
|
||||
public static void testAsymmetricEcSpecVariable(ECGenParameterSpec spec) throws java.security.NoSuchAlgorithmException, java.security.InvalidAlgorithmParameterException {
|
||||
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("EC");
|
||||
keyPairGen.initialize(spec); // sink is above where `spec` variable is initialized
|
||||
}
|
||||
|
||||
public static void testAsymmetricEcIntVariable(int keySize, KeyPairGenerator kpg) throws java.security.NoSuchAlgorithmException, java.security.InvalidAlgorithmParameterException {
|
||||
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("EC");
|
||||
keyPairGen.initialize(keySize); // $ hasInsufficientKeySize
|
||||
kpg.initialize(128); // $ MISSING: hasInsufficientKeySize
|
||||
}
|
||||
|
||||
public static void testAsymmetricEcIntLiteral(int keySize) throws java.security.NoSuchAlgorithmException, java.security.InvalidAlgorithmParameterException {
|
||||
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("EC");
|
||||
keyPairGen.initialize(keySize); // $ hasInsufficientKeySize
|
||||
}
|
||||
|
||||
public int getRSAKeySize(){ return 1024; }
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import java
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
import semmle.code.java.security.InsufficientKeySizeQuery
|
||||
|
||||
class InsufficientKeySizeTest extends InlineExpectationsTest {
|
||||
InsufficientKeySizeTest() { this = "InsufficientKeySize" }
|
||||
|
||||
override string getARelevantTag() { result = "hasInsufficientKeySize" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasInsufficientKeySize" and
|
||||
exists(DataFlow::PathNode source, DataFlow::PathNode sink |
|
||||
exists(KeySizeConfiguration cfg | cfg.hasFlowPath(source, sink))
|
||||
|
|
||||
sink.getNode().getLocation() = location and
|
||||
element = sink.getNode().toString() and
|
||||
value = ""
|
||||
)
|
||||
}
|
||||
}
|
||||
31
java/ql/test/query-tests/security/CWE-326/SignatureTest.java
Normal file
31
java/ql/test/query-tests/security/CWE-326/SignatureTest.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/* Adds tests to check for FPs related to RSA/DSA versus EC */
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Security;
|
||||
import java.security.Signature;
|
||||
|
||||
public class SignatureTest
|
||||
{
|
||||
|
||||
public void performTest()
|
||||
throws Exception
|
||||
{
|
||||
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");
|
||||
kpGen.initialize(2048); // Safe
|
||||
KeyPair kp = kpGen.generateKeyPair();
|
||||
|
||||
kpGen = KeyPairGenerator.getInstance("DSA", "BC");
|
||||
kpGen.initialize(2048); // Safe
|
||||
kp = kpGen.generateKeyPair();
|
||||
|
||||
kpGen = KeyPairGenerator.getInstance("EC", "BC");
|
||||
kpGen.initialize(256); // Safe
|
||||
kp = kpGen.generateKeyPair();
|
||||
|
||||
kpGen = KeyPairGenerator.getInstance("EC", "BC");
|
||||
kpGen.initialize(521); // Safe
|
||||
kp = kpGen.generateKeyPair();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user