mirror of
https://github.com/github/codeql.git
synced 2026-05-01 03:35:13 +02:00
Merge pull request #7136 from atorralba/atorralba/promote-insecure-trustmanager
Java: Promote Insecure TrustManager from experimental
This commit is contained in:
103
java/ql/lib/semmle/code/java/security/InsecureTrustManager.qll
Normal file
103
java/ql/lib/semmle/code/java/security/InsecureTrustManager.qll
Normal file
@@ -0,0 +1,103 @@
|
||||
/** Provides classes and predicates to reason about insecure `TrustManager`s. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.controlflow.Guards
|
||||
private import semmle.code.java.security.Encryption
|
||||
private import semmle.code.java.security.SecurityFlag
|
||||
|
||||
/** The creation of an insecure `TrustManager`. */
|
||||
abstract class InsecureTrustManagerSource extends DataFlow::Node { }
|
||||
|
||||
private class DefaultInsecureTrustManagerSource extends InsecureTrustManagerSource {
|
||||
DefaultInsecureTrustManagerSource() {
|
||||
this.asExpr().(ClassInstanceExpr).getConstructedType() instanceof InsecureX509TrustManager
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The use of a `TrustManager` in an SSL context.
|
||||
* Intentionally insecure connections are not considered sinks.
|
||||
*/
|
||||
abstract class InsecureTrustManagerSink extends DataFlow::Node {
|
||||
InsecureTrustManagerSink() { not isGuardedByInsecureFlag(this) }
|
||||
}
|
||||
|
||||
private class DefaultInsecureTrustManagerSink extends InsecureTrustManagerSink {
|
||||
DefaultInsecureTrustManagerSink() {
|
||||
exists(MethodAccess ma, Method m |
|
||||
m.hasName("init") and
|
||||
m.getDeclaringType() instanceof SSLContext and
|
||||
ma.getMethod() = m
|
||||
|
|
||||
ma.getArgument(1) = this.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if `node` is guarded by a flag that suggests an intentionally insecure use. */
|
||||
private predicate isGuardedByInsecureFlag(DataFlow::Node node) {
|
||||
exists(Guard g | g.controls(node.asExpr().getBasicBlock(), _) |
|
||||
g = getASecurityFeatureFlagGuard() or g = getAnInsecureTrustManagerFlagGuard()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* An insecure `X509TrustManager`.
|
||||
* An `X509TrustManager` is considered insecure if it never throws a `CertificateException`
|
||||
* and therefore implicitly trusts any certificate as valid.
|
||||
*/
|
||||
private class InsecureX509TrustManager extends RefType {
|
||||
InsecureX509TrustManager() {
|
||||
this.getASupertype*() instanceof X509TrustManager and
|
||||
exists(Method m |
|
||||
m.getDeclaringType() = this and
|
||||
m.hasName("checkServerTrusted") and
|
||||
not mayThrowCertificateException(m)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** The `java.security.cert.CertificateException` class. */
|
||||
private class CertificateException extends RefType {
|
||||
CertificateException() { this.hasQualifiedName("java.security.cert", "CertificateException") }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if:
|
||||
* - `m` may `throw` a `CertificateException`, or
|
||||
* - `m` calls another method that may throw, or
|
||||
* - `m` calls a method declared to throw a `CertificateException`, but for which no source is available
|
||||
*/
|
||||
private predicate mayThrowCertificateException(Method m) {
|
||||
exists(ThrowStmt throwStmt |
|
||||
throwStmt.getThrownExceptionType().getASupertype*() instanceof CertificateException
|
||||
|
|
||||
throwStmt.getEnclosingCallable() = m
|
||||
)
|
||||
or
|
||||
exists(Method otherMethod | m.polyCalls(otherMethod) |
|
||||
mayThrowCertificateException(otherMethod)
|
||||
or
|
||||
not otherMethod.fromSource() and
|
||||
otherMethod.getAnException().getType().getASupertype*() instanceof CertificateException
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Flags suggesting a deliberately insecure `TrustManager` usage.
|
||||
*/
|
||||
private class InsecureTrustManagerFlag extends FlagKind {
|
||||
InsecureTrustManagerFlag() { this = "InsecureTrustManagerFlag" }
|
||||
|
||||
bindingset[result]
|
||||
override string getAFlagName() {
|
||||
result
|
||||
.regexpMatch("(?i).*(secure|disable|selfCert|selfSign|validat|verif|trust|ignore|nocertificatecheck).*") and
|
||||
result != "equalsIgnoreCase"
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets a guard that represents a (likely) flag controlling an insecure `TrustManager` use. */
|
||||
private Guard getAnInsecureTrustManagerFlagGuard() {
|
||||
result = any(InsecureTrustManagerFlag flag).getAFlag().asExpr()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/** Provides taint tracking configurations to be used in Trust Manager queries. */
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.InsecureTrustManager
|
||||
|
||||
/**
|
||||
* A configuration to model the flow of an insecure `TrustManager`
|
||||
* to the initialization of an SSL context.
|
||||
*/
|
||||
class InsecureTrustManagerConfiguration extends DataFlow::Configuration {
|
||||
InsecureTrustManagerConfiguration() { this = "InsecureTrustManagerConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source instanceof InsecureTrustManagerSource
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof InsecureTrustManagerSink }
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
||||
(this.isSink(node) or this.isAdditionalFlowStep(node, _)) and
|
||||
node.getType() instanceof Array and
|
||||
c instanceof DataFlow::ArrayContent
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user