mirror of
https://github.com/github/codeql.git
synced 2026-04-27 17:55:19 +02:00
delete experimental files
This commit is contained in:
@@ -249,10 +249,7 @@ string getASecureAlgorithmName() {
|
||||
result =
|
||||
[
|
||||
"RSA", "SHA256", "SHA512", "CCM", "GCM", "AES(?)",
|
||||
"Blowfish", "ECIES" // ! Blowfish not actually secure based on https://rules.sonarsource.com/java/type/Vulnerability/RSPEC-4426 ??
|
||||
// ! hmm, other sources imply that it is secure...
|
||||
// ! also no DH here, etc.?
|
||||
// ! also is ECB matched with AES?
|
||||
"Blowfish", "ECIES"
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -1,264 +0,0 @@
|
||||
import semmle.code.java.security.Encryption
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
|
||||
//import DataFlow::PathGraph
|
||||
/**
|
||||
* Asymmetric (RSA, DSA, DH) key length data flow tracking configuration.
|
||||
*/
|
||||
class AsymmetricKeyTrackingConfiguration extends DataFlow::Configuration {
|
||||
AsymmetricKeyTrackingConfiguration() { this = "AsymmetricKeyTrackingConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
exists(IntegerLiteral integer, VarAccess var |
|
||||
integer.getIntValue() < 2048 and
|
||||
source.asExpr() = integer
|
||||
or
|
||||
var.getVariable().getInitializer().getUnderlyingExpr() instanceof IntegerLiteral and
|
||||
var.getVariable().getInitializer().getUnderlyingExpr().toString().toInt() < 2048 and
|
||||
source.asExpr() = var.getVariable().getInitializer()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof KeyPairGeneratorInitMethod and
|
||||
sink.asExpr() = ma.getArgument(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** The Java class `java.security.spec.ECGenParameterSpec`. */
|
||||
private class ECGenParameterSpec extends RefType {
|
||||
ECGenParameterSpec() { this.hasQualifiedName("java.security.spec", "ECGenParameterSpec") }
|
||||
}
|
||||
|
||||
/** The `init` method declared in `javax.crypto.KeyGenerator`. */
|
||||
private class KeyGeneratorInitMethod extends Method {
|
||||
KeyGeneratorInitMethod() {
|
||||
this.getDeclaringType() instanceof KeyGenerator and
|
||||
this.hasName("init")
|
||||
}
|
||||
}
|
||||
|
||||
/** The `initialize` method declared in `java.security.KeyPairGenerator`. */
|
||||
private class KeyPairGeneratorInitMethod extends Method {
|
||||
KeyPairGeneratorInitMethod() {
|
||||
this.getDeclaringType() instanceof KeyPairGenerator and
|
||||
this.hasName("initialize")
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the key size in the EC algorithm string */
|
||||
bindingset[algorithm]
|
||||
private 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. */
|
||||
private 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
|
||||
* an `initialize` method call.
|
||||
*/
|
||||
private 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]
|
||||
private predicate hasShortSymmetricKey(MethodAccess ma, string msg, string type) {
|
||||
ma.getMethod() instanceof KeyGeneratorInitMethod and
|
||||
// flow needed to correctly determine algorithm type and
|
||||
// not match to ANY symmetric algorithm (although doesn't really matter since only have AES currently...)
|
||||
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
|
||||
(
|
||||
// VarAccess case needed to handle FN of key-size stored in a variable
|
||||
// Note: cannot use CompileTimeConstantExpr since will miss cases when variable is not a compile-time constant
|
||||
// (e.g. not declared `final` in Java)
|
||||
exists(VarAccess var |
|
||||
var.getVariable().getInitializer().getUnderlyingExpr() instanceof IntegerLiteral and
|
||||
var.getVariable().getInitializer().getUnderlyingExpr().toString().toInt() < 128 and
|
||||
ma.getArgument(0) = var
|
||||
)
|
||||
or
|
||||
// exists(CompileTimeConstantExpr var |
|
||||
// //var.getUnderlyingExpr() instanceof IntegerLiteral and // can't include this...
|
||||
// var.getIntValue() < 128 and
|
||||
// ma.getArgument(0) = var
|
||||
// )
|
||||
// or
|
||||
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.
|
||||
*/
|
||||
private 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]
|
||||
private predicate hasShortAsymmetricKeyPair(MethodAccess ma, string msg, string type) {
|
||||
ma.getMethod() instanceof KeyPairGeneratorInitMethod and
|
||||
//ma.getQualifier() instanceof JavaSecurityKeyPairGenerator and
|
||||
//ma.getQualifier().getBasicBlock() instanceof JavaSecurityKeyPairGenerator and
|
||||
// * USE BELOW
|
||||
ma.getQualifier().getBasicBlock().getAPredecessor() instanceof JavaSecurityKeyPairGenerator and
|
||||
// * USE ABOVE
|
||||
//ma.getQualifier().getBasicBlock().getNode(2) instanceof JavaSecurityKeyPairGenerator and
|
||||
// ma.getQualifier()
|
||||
// .getBasicBlock()
|
||||
// .getANode()
|
||||
// .(JavaSecurityKeyPairGenerator)
|
||||
// .getAlgoSpec()
|
||||
// .(StringLiteral)
|
||||
// .getValue()
|
||||
// .toUpperCase() = type and
|
||||
//ma.getQualifier().getBasicBlock().getAPredecessor() instanceof JavaSecurityKeyPairGenerator and
|
||||
// * USE BELOW
|
||||
ma.getQualifier()
|
||||
.getBasicBlock()
|
||||
.getAPredecessor()
|
||||
.(JavaSecurityKeyPairGenerator)
|
||||
.getAlgoSpec()
|
||||
.(StringLiteral)
|
||||
.getValue()
|
||||
.toUpperCase() = type and
|
||||
// * USE ABOVE
|
||||
// flow needed to correctly determine algorithm type and
|
||||
// not match to ANY asymmetric algorithm
|
||||
// * REMOVE BELOW
|
||||
// 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
|
||||
// * REMOVE ABOVE
|
||||
// VarAccess case needed to handle FN of key-size stored in a variable
|
||||
// Note: cannot use CompileTimeConstantExpr since will miss cases when variable is not a compile-time constant
|
||||
// (e.g. not declared `final` in Java)
|
||||
(
|
||||
exists(VarAccess var |
|
||||
var.getVariable().getInitializer().getUnderlyingExpr() instanceof IntegerLiteral and
|
||||
var.getVariable().getInitializer().getUnderlyingExpr().toString().toInt() < 2048 and
|
||||
ma.getArgument(0) = var
|
||||
)
|
||||
or
|
||||
ma.getArgument(0).(IntegerLiteral).getIntValue() < 2048
|
||||
// or
|
||||
// exists(
|
||||
// AsymmetricKeyTrackingConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
// |
|
||||
// cfg.hasFlowPath(source, sink)
|
||||
// )
|
||||
) 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.
|
||||
*/
|
||||
private 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.
|
||||
*/
|
||||
private 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.
|
||||
*/
|
||||
private 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."
|
||||
}
|
||||
|
||||
// ! refactor this so can use 'path-problem' select clause instead?
|
||||
predicate hasInsufficientKeySize(Expr e, string msg) {
|
||||
hasShortAESKey(e, msg) or
|
||||
hasShortDsaKeyPair(e, msg) or
|
||||
hasShortRsaKeyPair(e, msg) or
|
||||
hasShortECKeyPair(e, msg)
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
import semmle.code.java.security.Encryption
|
||||
import semmle.code.java.dataflow.TaintTracking2
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
|
||||
// TODO:
|
||||
// todo #0: find a better way to combine the two needed taint-tracking configs so can go back to having a path-graph...
|
||||
// todo #1: make representation of source that can be shared across the configs
|
||||
// todo #2: make representation of sink that can be shared across the configs
|
||||
// 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.)
|
||||
// todo #4: refactor to be more like the Python version? (or not possible because of lack of DataFlow::Node for void method in Java?)
|
||||
// ******* DATAFLOW BELOW *************************************************************************
|
||||
/**
|
||||
* Asymmetric (RSA, DSA, DH) key length data flow tracking configuration.
|
||||
*/
|
||||
class AsymmetricKeyTrackingConfiguration extends TaintTracking2::Configuration {
|
||||
AsymmetricKeyTrackingConfiguration() { this = "AsymmetricKeyTrackingConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
exists(ClassInstanceExpr rsaGenParamSpec |
|
||||
rsaGenParamSpec.getConstructedType() instanceof RSAGenParameterSpec and // ! double-check if should just use getType() instead
|
||||
rsaGenParamSpec.getArgument(0).(IntegerLiteral).getIntValue() < 2048 and
|
||||
source.asExpr() = rsaGenParamSpec
|
||||
)
|
||||
or
|
||||
source.asExpr().(IntegerLiteral).getIntValue() < 2048
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma, VarAccess va |
|
||||
ma.getMethod() instanceof KeyPairGeneratorInitMethod and
|
||||
//ma.getFile().getBaseName().matches("SignatureTest.java") and
|
||||
// va.getVariable()
|
||||
// .getAnAssignedValue()
|
||||
// .(JavaSecurityKeyPairGenerator)
|
||||
// .getAlgoSpec()
|
||||
// .(StringLiteral)
|
||||
// .getValue()
|
||||
// .toUpperCase()
|
||||
// .matches(["RSA", "DSA", "DH"]) and
|
||||
// ma.getQualifier() = va and
|
||||
exists(
|
||||
JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorInitConfiguration kpgConfig,
|
||||
DataFlow::PathNode source, DataFlow::PathNode dest
|
||||
|
|
||||
jpg.getAlgoSpec().(StringLiteral).getValue().toUpperCase().matches(["RSA", "DSA", "DH"]) and
|
||||
source.getNode().asExpr() = jpg and
|
||||
dest.getNode().asExpr() = ma.getQualifier() and
|
||||
kpgConfig.hasFlowPath(source, dest)
|
||||
) and
|
||||
sink.asExpr() = ma.getArgument(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// predicate hasInsufficientKeySize(string msg) { hasShortAsymmetricKeyPair(msg) }
|
||||
// predicate hasShortAsymmetricKeyPair(string msg) {
|
||||
// exists(AsymmetricKeyTrackingConfiguration config1, DataFlow::Node source, DataFlow::Node sink |
|
||||
// config1.hasFlow(source, sink)
|
||||
// ) and
|
||||
// msg = "Key size should be at least 2048 bits for " + "___" + " encryption."
|
||||
// }
|
||||
/**
|
||||
* Asymmetric (EC) key length data flow tracking configuration.
|
||||
*/
|
||||
class AsymmetricECCKeyTrackingConfiguration extends TaintTracking2::Configuration {
|
||||
AsymmetricECCKeyTrackingConfiguration() { this = "AsymmetricECCKeyTrackingConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
exists(ClassInstanceExpr ecGenParamSpec |
|
||||
getECKeySize(ecGenParamSpec.getArgument(0).(StringLiteral).getValue()) < 256 and // ! can generate EC with just the keysize and not the curve apparently... (based on netty/netty FP example)
|
||||
source.asExpr() = ecGenParamSpec
|
||||
)
|
||||
or
|
||||
source.asExpr().(IntegerLiteral).getIntValue() < 256
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma, VarAccess va |
|
||||
ma.getMethod() instanceof KeyPairGeneratorInitMethod and
|
||||
//ma.getArgument(0).getType() instanceof ECGenParameterSpec and // ! can generate EC with just the keysize and not the curve apparently... (based on netty/netty FP example)
|
||||
// va.getVariable()
|
||||
// .getAnAssignedValue()
|
||||
// .(JavaSecurityKeyPairGenerator)
|
||||
// .getAlgoSpec()
|
||||
// .(StringLiteral)
|
||||
// .getValue()
|
||||
// .toUpperCase()
|
||||
// .matches(["EC%"]) and
|
||||
// ma.getQualifier() = va and
|
||||
exists(
|
||||
JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorInitConfiguration kpgConfig,
|
||||
DataFlow::PathNode source, DataFlow::PathNode dest
|
||||
|
|
||||
jpg.getAlgoSpec().(StringLiteral).getValue().toUpperCase().matches("EC%") and
|
||||
source.getNode().asExpr() = jpg and
|
||||
dest.getNode().asExpr() = ma.getQualifier() and
|
||||
kpgConfig.hasFlowPath(source, dest)
|
||||
) and
|
||||
sink.asExpr() = ma.getArgument(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Symmetric (AES) key length data flow tracking configuration.
|
||||
*/
|
||||
class SymmetricKeyTrackingConfiguration extends TaintTracking2::Configuration {
|
||||
SymmetricKeyTrackingConfiguration() { this = "SymmetricKeyTrackingConfiguration2" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr().(IntegerLiteral).getIntValue() < 128
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma, VarAccess va |
|
||||
ma.getMethod() instanceof KeyGeneratorInitMethod and
|
||||
// va.getVariable()
|
||||
// .getAnAssignedValue()
|
||||
// .(JavaxCryptoKeyGenerator)
|
||||
// .getAlgoSpec()
|
||||
// .(StringLiteral)
|
||||
// .getValue()
|
||||
// .toUpperCase()
|
||||
// .matches(["AES"]) and
|
||||
// ma.getQualifier() = va and
|
||||
exists(
|
||||
JavaxCryptoKeyGenerator jcg, KeyGeneratorInitConfiguration kgConfig,
|
||||
DataFlow::PathNode source, DataFlow::PathNode dest
|
||||
|
|
||||
jcg.getAlgoSpec().(StringLiteral).getValue().toUpperCase().matches("AES") and
|
||||
source.getNode().asExpr() = jcg and
|
||||
dest.getNode().asExpr() = ma.getQualifier() and
|
||||
kgConfig.hasFlowPath(source, dest)
|
||||
) and
|
||||
sink.asExpr() = ma.getArgument(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ! below doesn't work for some reason...
|
||||
// predicate hasInsufficientKeySize2(DataFlow::PathNode source, DataFlow::PathNode sink) {
|
||||
// exists(AsymmetricKeyTrackingConfiguration config1 | config1.hasFlowPath(source, sink))
|
||||
// or
|
||||
// exists(SymmetricKeyTrackingConfiguration config2 | config2.hasFlowPath(source, sink))
|
||||
// }
|
||||
// ******** Need the below for the above ********
|
||||
// ! move to Encryption.qll?
|
||||
/** The Java class `java.security.spec.ECGenParameterSpec`. */
|
||||
private class ECGenParameterSpec extends RefType {
|
||||
ECGenParameterSpec() { this.hasQualifiedName("java.security.spec", "ECGenParameterSpec") }
|
||||
}
|
||||
|
||||
/** The Java class `java.security.spec.ECGenParameterSpec`. */
|
||||
private class RSAGenParameterSpec extends RefType {
|
||||
RSAGenParameterSpec() { this.hasQualifiedName("java.security.spec", "RSAKeyGenParameterSpec") }
|
||||
}
|
||||
|
||||
// ! move to Encryption.qll?
|
||||
/** Returns the key size in the EC algorithm string */
|
||||
bindingset[algorithm]
|
||||
private 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()
|
||||
}
|
||||
|
||||
// ! move to Encryption.qll?
|
||||
/** The `init` method declared in `javax.crypto.KeyGenerator`. */
|
||||
private class KeyGeneratorInitMethod extends Method {
|
||||
KeyGeneratorInitMethod() {
|
||||
this.getDeclaringType() instanceof KeyGenerator and
|
||||
this.hasName("init")
|
||||
}
|
||||
}
|
||||
|
||||
// ! move to Encryption.qll?
|
||||
/** The `initialize` method declared in `java.security.KeyPairGenerator`. */
|
||||
private class KeyPairGeneratorInitMethod extends Method {
|
||||
KeyPairGeneratorInitMethod() {
|
||||
this.getDeclaringType() instanceof KeyPairGenerator and
|
||||
this.hasName("initialize")
|
||||
}
|
||||
}
|
||||
|
||||
// ******* DATAFLOW ABOVE *************************************************************************
|
||||
// ************************************************************************************************
|
||||
// ************************************************************************************************
|
||||
// ************************************************************************************************
|
||||
// ************************************************************************************************
|
||||
// ************************************************************************************************
|
||||
// ******* OLD/UNUSED OR EXPERIMENTAL CODE BELOW **************************************************
|
||||
class UnsafeSymmetricKeySize extends IntegerLiteral {
|
||||
UnsafeSymmetricKeySize() { this.getIntValue() < 128 }
|
||||
}
|
||||
|
||||
class UnsafeAsymmetricKeySize extends IntegerLiteral {
|
||||
UnsafeAsymmetricKeySize() { this.getIntValue() < 2048 }
|
||||
}
|
||||
|
||||
/** Taint configuration tracking flow from a key generator to a `init` method call. */
|
||||
private 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
|
||||
* an `initialize` method call.
|
||||
*/
|
||||
private 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()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
import semmle.code.java.security.Encryption
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.DataFlow3
|
||||
|
||||
/** The Java class `java.security.spec.ECGenParameterSpec`. */
|
||||
private class ECGenParameterSpec extends RefType {
|
||||
ECGenParameterSpec() { this.hasQualifiedName("java.security.spec", "ECGenParameterSpec") }
|
||||
}
|
||||
|
||||
/** The `init` method declared in `javax.crypto.KeyGenerator`. */
|
||||
private class KeyGeneratorInitMethod extends Method {
|
||||
KeyGeneratorInitMethod() {
|
||||
this.getDeclaringType() instanceof KeyGenerator and
|
||||
this.hasName("init")
|
||||
}
|
||||
}
|
||||
|
||||
/** The `initialize` method declared in `java.security.KeyPairGenerator`. */
|
||||
private class KeyPairGeneratorInitMethod extends Method {
|
||||
KeyPairGeneratorInitMethod() {
|
||||
this.getDeclaringType() instanceof KeyPairGenerator and
|
||||
this.hasName("initialize")
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the key size in the EC algorithm string */
|
||||
bindingset[algorithm]
|
||||
private 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. */
|
||||
private 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
|
||||
* an `initialize` method call.
|
||||
*/
|
||||
private 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]
|
||||
private 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
|
||||
//ma.getArgument(0) = var and // ! me
|
||||
//var.getVariable().getInitializer().getUnderlyingExpr() instanceof IntegerLiteral and // ! me
|
||||
cc.hasFlowPath(source, dest) //and
|
||||
//var.getVariable().getInitializer().getUnderlyingExpr().toString().toInt() < 128 // ! me
|
||||
) and
|
||||
exists(VarAccess var |
|
||||
var.getVariable().getInitializer().getUnderlyingExpr() instanceof IntegerLiteral and
|
||||
var.getVariable().getInitializer().getUnderlyingExpr().toString().toInt() < 128 and
|
||||
//DataFlow3::localExprFlow(var, ma.getArgument(0)) and
|
||||
ma.getArgument(0) = var
|
||||
//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.
|
||||
*/
|
||||
private 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]
|
||||
private 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.
|
||||
*/
|
||||
private 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.
|
||||
*/
|
||||
private 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.
|
||||
*/
|
||||
private 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."
|
||||
}
|
||||
|
||||
// ! refactor this so can use 'path-problem' select clause instead?
|
||||
predicate hasInsufficientKeySize(Expr e, string msg) {
|
||||
hasShortAESKey(e, msg) or
|
||||
hasShortDsaKeyPair(e, msg) or
|
||||
hasShortRsaKeyPair(e, msg) or
|
||||
hasShortECKeyPair(e, msg)
|
||||
}
|
||||
Reference in New Issue
Block a user