|
10 | 10 | */ |
11 | 11 |
|
12 | 12 | import java |
13 | | -import semmle.code.java.controlflow.Guards |
14 | 13 | import semmle.code.java.dataflow.DataFlow |
15 | | -import semmle.code.java.dataflow.FlowSources |
16 | | -import semmle.code.java.security.Encryption |
17 | | -import semmle.code.java.security.SecurityFlag |
| 14 | +import semmle.code.java.security.InsecureTrustManagerQuery |
18 | 15 | import DataFlow::PathGraph |
19 | 16 |
|
20 | | -/** |
21 | | - * An insecure `X509TrustManager`. |
22 | | - * An `X509TrustManager` is considered insecure if it never throws a `CertificateException` |
23 | | - * and therefore implicitly trusts any certificate as valid. |
24 | | - */ |
25 | | -class InsecureX509TrustManager extends RefType { |
26 | | - InsecureX509TrustManager() { |
27 | | - this.getASupertype*() instanceof X509TrustManager and |
28 | | - exists(Method m | |
29 | | - m.getDeclaringType() = this and |
30 | | - m.hasName("checkServerTrusted") and |
31 | | - not mayThrowCertificateException(m) |
32 | | - ) |
33 | | - } |
34 | | -} |
35 | | - |
36 | | -/** The `java.security.cert.CertificateException` class. */ |
37 | | -private class CertificateException extends RefType { |
38 | | - CertificateException() { this.hasQualifiedName("java.security.cert", "CertificateException") } |
39 | | -} |
40 | | - |
41 | | -/** |
42 | | - * Holds if: |
43 | | - * - `m` may `throw` a `CertificateException`, or |
44 | | - * - `m` calls another method that may throw, or |
45 | | - * - `m` calls a method declared to throw a `CertificateException`, but for which no source is available |
46 | | - */ |
47 | | -private predicate mayThrowCertificateException(Method m) { |
48 | | - exists(ThrowStmt throwStmt | |
49 | | - throwStmt.getThrownExceptionType().getASupertype*() instanceof CertificateException |
50 | | - | |
51 | | - throwStmt.getEnclosingCallable() = m |
52 | | - ) |
53 | | - or |
54 | | - exists(Method otherMethod | m.polyCalls(otherMethod) | |
55 | | - mayThrowCertificateException(otherMethod) |
56 | | - or |
57 | | - not otherMethod.fromSource() and |
58 | | - otherMethod.getAnException().getType().getASupertype*() instanceof CertificateException |
59 | | - ) |
60 | | -} |
61 | | - |
62 | | -/** |
63 | | - * A configuration to model the flow of an `InsecureX509TrustManager` to an `SSLContext.init` call. |
64 | | - */ |
65 | | -class InsecureTrustManagerConfiguration extends TaintTracking::Configuration { |
66 | | - InsecureTrustManagerConfiguration() { this = "InsecureTrustManagerConfiguration" } |
67 | | - |
68 | | - override predicate isSource(DataFlow::Node source) { |
69 | | - source.asExpr().(ClassInstanceExpr).getConstructedType() instanceof InsecureX509TrustManager |
70 | | - } |
71 | | - |
72 | | - override predicate isSink(DataFlow::Node sink) { |
73 | | - exists(MethodAccess ma, Method m | |
74 | | - m.hasName("init") and |
75 | | - m.getDeclaringType() instanceof SSLContext and |
76 | | - ma.getMethod() = m |
77 | | - | |
78 | | - ma.getArgument(1) = sink.asExpr() |
79 | | - ) |
80 | | - } |
81 | | -} |
82 | | - |
83 | | -/** |
84 | | - * Flags suggesting a deliberately insecure `TrustManager` usage. |
85 | | - */ |
86 | | -private class InsecureTrustManagerFlag extends FlagKind { |
87 | | - InsecureTrustManagerFlag() { this = "InsecureTrustManagerFlag" } |
88 | | - |
89 | | - bindingset[result] |
90 | | - override string getAFlagName() { |
91 | | - result |
92 | | - .regexpMatch("(?i).*(secure|disable|selfCert|selfSign|validat|verif|trust|ignore|nocertificatecheck).*") and |
93 | | - result != "equalsIgnoreCase" |
94 | | - } |
95 | | -} |
96 | | - |
97 | | -/** Gets a guard that represents a (likely) flag controlling an insecure `TrustManager` use. */ |
98 | | -private Guard getAnInsecureTrustManagerFlagGuard() { |
99 | | - result = any(InsecureTrustManagerFlag flag).getAFlag().asExpr() |
100 | | -} |
101 | | - |
102 | | -/** Holds if `node` is guarded by a flag that suggests an intentionally insecure use. */ |
103 | | -private predicate isNodeGuardedByFlag(DataFlow::Node node) { |
104 | | - exists(Guard g | g.controls(node.asExpr().getBasicBlock(), _) | |
105 | | - g = getASecurityFeatureFlagGuard() or g = getAnInsecureTrustManagerFlagGuard() |
106 | | - ) |
107 | | -} |
108 | | - |
109 | | -from |
110 | | - DataFlow::PathNode source, DataFlow::PathNode sink, InsecureTrustManagerConfiguration cfg, |
111 | | - RefType trustManager |
112 | | -where |
113 | | - cfg.hasFlowPath(source, sink) and |
114 | | - not isNodeGuardedByFlag(sink.getNode()) and |
115 | | - trustManager = source.getNode().asExpr().(ClassInstanceExpr).getConstructedType() |
116 | | -select sink, source, sink, "$@ that is defined $@ and trusts any certificate, is used here.", |
117 | | - source, "This trustmanager", trustManager, "here" |
| 17 | +from DataFlow::PathNode source, DataFlow::PathNode sink |
| 18 | +where any(InsecureTrustManagerConfiguration cfg).hasFlowPath(source, sink) |
| 19 | +select sink, source, sink, "This $@, that is defined $@, trusts any certificate and is used here.", |
| 20 | + source, "TrustManager", source.getNode().asExpr().(ClassInstanceExpr).getConstructedType(), "here" |
0 commit comments