Big refactor:

- Move classes and predicates to appropriate libraries
- Overhaul the endpoint identification algorithm logic to use taint tracking
- Adapt tests
This commit is contained in:
Tony Torralba
2021-06-21 17:36:50 +02:00
parent e0f4c73aed
commit 4313baf622
7 changed files with 494 additions and 169 deletions

View File

@@ -12,158 +12,25 @@
*/
import java
import semmle.code.java.security.Encryption
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.security.UnsafeCertTrust
class SSLEngine extends RefType {
SSLEngine() { this.hasQualifiedName("javax.net.ssl", "SSLEngine") }
}
class SslEndpointIdentificationFlowConfig extends TaintTracking::Configuration {
SslEndpointIdentificationFlowConfig() { this = "SslEndpointIdentificationFlowConfig" }
class Socket extends RefType {
Socket() { this.hasQualifiedName("java.net", "Socket") }
}
override predicate isSource(DataFlow::Node source) { source instanceof SslConnectionInit }
class SocketFactory extends RefType {
SocketFactory() { this.hasQualifiedName("javax.net", "SocketFactory") }
}
override predicate isSink(DataFlow::Node sink) { sink instanceof SslConnectionCreation }
class SSLSocket extends RefType {
SSLSocket() { this.hasQualifiedName("javax.net.ssl", "SSLSocket") }
}
/**
* has setEndpointIdentificationAlgorithm set correctly
*/
predicate setEndpointIdentificationAlgorithm(MethodAccess createSSL) {
exists(
Variable sslo, MethodAccess ma, Variable sslparams //setSSLParameters with valid setEndpointIdentificationAlgorithm set
|
createSSL = sslo.getAnAssignedValue() and
ma.getQualifier() = sslo.getAnAccess() and
ma.getMethod().hasName("setSSLParameters") and
ma.getArgument(0) = sslparams.getAnAccess() and
exists(MethodAccess setepa |
setepa.getQualifier() = sslparams.getAnAccess() and
setepa.getMethod().hasName("setEndpointIdentificationAlgorithm") and
not setepa.getArgument(0) instanceof NullLiteral
)
)
}
/**
* has setEndpointIdentificationAlgorithm set correctly
*/
predicate hasEndpointIdentificationAlgorithm(Variable ssl) {
exists(
MethodAccess ma, Variable sslparams //setSSLParameters with valid setEndpointIdentificationAlgorithm set
|
ma.getQualifier() = ssl.getAnAccess() and
ma.getMethod().hasName("setSSLParameters") and
ma.getArgument(0) = sslparams.getAnAccess() and
exists(MethodAccess setepa |
setepa.getQualifier() = sslparams.getAnAccess() and
setepa.getMethod().hasName("setEndpointIdentificationAlgorithm") and
not setepa.getArgument(0) instanceof NullLiteral
)
)
}
/**
* Cast of Socket to SSLSocket
*/
predicate sslCast(MethodAccess createSSL) {
exists(Variable ssl, CastExpr ce |
ce.getExpr() = createSSL and
ce.getControlFlowNode().getASuccessor().(VariableAssign).getDestVar() = ssl and
ssl.getType() instanceof SSLSocket //With a type cast `SSLSocket socket = (SSLSocket) socketFactory.createSocket("www.example.com", 443)`
)
}
/**
* SSL object is created in a separate method call or in the same method
*/
predicate hasFlowPath(MethodAccess createSSL, Variable ssl) {
(
createSSL = ssl.getAnAssignedValue()
or
exists(CastExpr ce |
ce.getExpr() = createSSL and
ce.getControlFlowNode().getASuccessor().(VariableAssign).getDestVar() = ssl //With a type cast like SSLSocket socket = (SSLSocket) socketFactory.createSocket("www.example.com", 443);
)
)
or
exists(MethodAccess tranm |
createSSL.getEnclosingCallable() = tranm.getMethod() and
tranm.getControlFlowNode().getASuccessor().(VariableAssign).getDestVar() = ssl and
not setEndpointIdentificationAlgorithm(createSSL) //Check the scenario of invocation before used in the current method
)
}
/**
* Not have the SSLParameter set
*/
predicate hasNoEndpointIdentificationSet(MethodAccess createSSL, Variable ssl) {
//No setSSLParameters set
hasFlowPath(createSSL, ssl) and
not exists(MethodAccess ma |
ma.getQualifier() = ssl.getAnAccess() and
ma.getMethod().hasName("setSSLParameters")
)
or
//No endpointIdentificationAlgorithm set with setSSLParameters
hasFlowPath(createSSL, ssl) and
not setEndpointIdentificationAlgorithm(createSSL)
}
/**
* The setEndpointIdentificationAlgorithm method of SSLParameters with the ssl engine or socket
*/
class SSLEndpointIdentificationNotSet extends MethodAccess {
SSLEndpointIdentificationNotSet() {
(
this.getMethod().hasName("createSSLEngine") and
this.getMethod().getDeclaringType() instanceof SSLContext //createEngine method of SSLContext
or
this.getMethod().hasName("createSocket") and
this.getMethod().getDeclaringType() instanceof SocketFactory and
this.getMethod().getReturnType() instanceof Socket and
sslCast(this) //createSocket method of SocketFactory
) and
exists(Variable ssl |
hasNoEndpointIdentificationSet(this, ssl) and //Not set in itself
not exists(VariableAssign ar, Variable newSsl |
ar.getSource() = this.getCaller().getAReference() and
ar.getDestVar() = newSsl and
hasEndpointIdentificationAlgorithm(newSsl) //Not set in its caller either
)
) and
not exists(MethodAccess ma | ma.getMethod() instanceof HostnameVerifierVerify) //Reduce false positives since this method access set default hostname verifier
override predicate isSanitizer(DataFlow::Node sanitizer) {
sanitizer.asExpr() instanceof SslConnectionWithSafeSslParameters
}
}
class RabbitMQConnectionFactory extends RefType {
RabbitMQConnectionFactory() { this.hasQualifiedName("com.rabbitmq.client", "ConnectionFactory") }
}
/**
* The com.rabbitmq.client.ConnectionFactory useSslProtocol method access without enableHostnameVerification
*/
class RabbitMQEnableHostnameVerificationNotSet extends MethodAccess {
RabbitMQEnableHostnameVerificationNotSet() {
this.getMethod().hasName("useSslProtocol") and
this.getMethod().getDeclaringType() instanceof RabbitMQConnectionFactory and
exists(Variable v |
v.getType() instanceof RabbitMQConnectionFactory and
this.getQualifier() = v.getAnAccess() and
not exists(MethodAccess ma |
ma.getMethod().hasName("enableHostnameVerification") and
ma.getQualifier() = v.getAnAccess()
)
)
}
}
from MethodAccess aa
from Expr unsafeConfig
where
aa instanceof SSLEndpointIdentificationNotSet or
aa instanceof RabbitMQEnableHostnameVerificationNotSet
select aa, "Unsafe configuration of trusted certificates"
unsafeConfig instanceof RabbitMQEnableHostnameVerificationNotSet or
exists(SslEndpointIdentificationFlowConfig config |
config.hasFlowTo(DataFlow::exprNode(unsafeConfig))
)
select unsafeConfig, "Unsafe configuration of trusted certificates"