-
Notifications
You must be signed in to change notification settings - Fork 2k
Java: Promote Insecure TrustManager from experimental #7136
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
7cd05fb
ab4dc30
d58bb47
77c2b43
7a1a45f
c105d71
967308f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| 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() | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| /** Provides taint tracking configurations to be used in Trust Manager queries. */ | ||
|
|
||
| import java | ||
| import semmle.code.java.dataflow.FlowSources | ||
| import semmle.code.java.security.Encryption | ||
| 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 TaintTracking::Configuration { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this be changed to
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
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
}(which is actually part of the default implicit reads in We could even restrict Of course, the trade-off would be that, if for some reason the insecure @aschackmull what do you think is more appropriate in this case?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did this in 967308f. |
||
| InsecureTrustManagerConfiguration() { this = "InsecureTrustManagerConfiguration" } | ||
|
|
||
| override predicate isSource(DataFlow::Node source) { | ||
| source instanceof InsecureTrustManagerSource | ||
| } | ||
|
|
||
| override predicate isSink(DataFlow::Node sink) { sink instanceof InsecureTrustManagerSink } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commenting here, because I can not comment down there, because the code did not change.
When I coded this, there was no good place for
CertificateException(Line 37/61), maybe there is now a better place or common library?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the moment, this is something that is only used here, and it doesn't seem to fit in any of the currently existing libraries. Nonetheless, this is definitely something to keep in mind if, in the future,
CertificateExceptionneeds to be reused, or more classes fromjava.security.certare modeled. Thanks!