Skip to content

Commit be21b26

Browse files
authored
Merge pull request #10045 from github/alexdenisov/swift-cwe-757
Swift: CWE-757: insecure TLS configuration
2 parents 818601b + 568eb3a commit be21b26

File tree

6 files changed

+355
-0
lines changed

6 files changed

+355
-0
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>TLS v1.0 and v1.1 versions are known to be vulnerable.</p>
7+
</overview>
8+
<recommendation>
9+
10+
<p>Use <code>tls_protocol_version_t.TLSv12</code> or <code>tls_protocol_version_t.TLSv13</code> when configuring <code>URLSession</code>.</p>
11+
12+
</recommendation>
13+
<example>
14+
15+
<p>Specify a newer <code>tls_protocol_version_t</code> explicitly, or omit it completely as the OS will use secure defaults.</p>
16+
17+
<sample src="SecureTLS.swift" />
18+
19+
</example>
20+
<references>
21+
22+
<li>
23+
<a href="https://support.apple.com/en-gb/guide/security/sec100a75d12/web">Apple Platform Security - TLS security</a>
24+
<a href="https://developer.apple.com/documentation/security/preventing_insecure_network_connections">Preventing Insecure Network Connections</a>
25+
</li>
26+
27+
</references>
28+
</qhelp>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* @name Insecure TLS configuration
3+
* @description TLS v1.0 and v1.1 versions are known to be vulnerable. TLS v1.2 or v1.3 should be used instead.
4+
* @kind path-problem
5+
* @problem.severity error
6+
* @security-severity 7.5
7+
* @precision high
8+
* @id swift/insecure-tls
9+
* @tags security
10+
* external/cwe/cwe-757
11+
*/
12+
13+
import swift
14+
import codeql.swift.dataflow.DataFlow
15+
import codeql.swift.dataflow.TaintTracking
16+
import codeql.swift.dataflow.FlowSources
17+
import DataFlow::PathGraph
18+
19+
/**
20+
* A taint config to detect insecure configuration of `NSURLSessionConfiguration`
21+
*/
22+
class InsecureTlsConfig extends TaintTracking::Configuration {
23+
InsecureTlsConfig() { this = "InsecureTLSConfig" }
24+
25+
/**
26+
* Holds for enum values that represent an insecure version of TLS
27+
*/
28+
override predicate isSource(DataFlow::Node node) {
29+
exists(MethodRefExpr expr, EnumElementDecl enum, string enumName |
30+
node.asExpr() = expr and
31+
expr.getMember() = enum and
32+
enumName = enum.getName() and
33+
enumName in ["TLSv10", "TLSv11", "tlsProtocol10", "tlsProtocol11"]
34+
)
35+
}
36+
37+
/**
38+
* Holds for assignment of TLS-related properties of `NSURLSessionConfiguration`
39+
*/
40+
override predicate isSink(DataFlow::Node node) {
41+
exists(AssignExpr assign, MemberRefExpr member, string memberName |
42+
assign.getSource() = node.asExpr() and
43+
assign.getDest() = member and
44+
memberName = member.getMember().(ConcreteVarDecl).getName() and
45+
memberName in [
46+
"tlsMinimumSupportedProtocolVersion", "tlsMinimumSupportedProtocol",
47+
"tlsMaximumSupportedProtocolVersion", "tlsMaximumSupportedProtocol"
48+
]
49+
)
50+
}
51+
}
52+
53+
from InsecureTlsConfig config, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode
54+
where config.hasFlowPath(sourceNode, sinkNode)
55+
select sinkNode.getNode(), sourceNode, sinkNode, "This TLS configuration is insecure."
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Set TLS version explicitly
2+
func createURLSession() -> URLSession {
3+
let config = URLSessionConfiguration.default
4+
config.tlsMinimumSupportedProtocolVersion = tls_protocol_version_t.TLSv13
5+
return URLSession(configuration: config)
6+
}
7+
8+
// Use the secure OS defaults
9+
func createURLSession() -> URLSession {
10+
let config = URLSessionConfiguration.default
11+
return URLSession(configuration: config)
12+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
edges
2+
| InsecureTLS.swift:19:7:19:7 | value : | file://:0:0:0:0 | value |
3+
| InsecureTLS.swift:20:7:20:7 | value : | file://:0:0:0:0 | value |
4+
| InsecureTLS.swift:22:7:22:7 | value : | file://:0:0:0:0 | value |
5+
| InsecureTLS.swift:23:7:23:7 | value : | file://:0:0:0:0 | value |
6+
| InsecureTLS.swift:40:47:40:70 | .TLSv10 : | InsecureTLS.swift:19:7:19:7 | value : |
7+
| InsecureTLS.swift:45:47:45:70 | .TLSv11 : | InsecureTLS.swift:19:7:19:7 | value : |
8+
| InsecureTLS.swift:57:47:57:70 | .TLSv10 : | InsecureTLS.swift:20:7:20:7 | value : |
9+
| InsecureTLS.swift:64:40:64:52 | .tlsProtocol10 : | InsecureTLS.swift:22:7:22:7 | value : |
10+
| InsecureTLS.swift:76:40:76:52 | .tlsProtocol10 : | InsecureTLS.swift:23:7:23:7 | value : |
11+
| InsecureTLS.swift:102:10:102:33 | .TLSv10 : | InsecureTLS.swift:111:47:111:64 | call to getBadTLSVersion() |
12+
| InsecureTLS.swift:102:10:102:33 | .TLSv10 : | InsecureTLS.swift:111:47:111:64 | call to getBadTLSVersion() : |
13+
| InsecureTLS.swift:111:47:111:64 | call to getBadTLSVersion() : | InsecureTLS.swift:19:7:19:7 | value : |
14+
| InsecureTLS.swift:121:55:121:66 | version : | InsecureTLS.swift:122:47:122:47 | version |
15+
| InsecureTLS.swift:121:55:121:66 | version : | InsecureTLS.swift:122:47:122:47 | version : |
16+
| InsecureTLS.swift:122:47:122:47 | version : | InsecureTLS.swift:19:7:19:7 | value : |
17+
| InsecureTLS.swift:127:25:127:48 | .TLSv11 : | InsecureTLS.swift:121:55:121:66 | version : |
18+
| InsecureTLS.swift:158:7:158:7 | self [TLSVersion] : | file://:0:0:0:0 | self [TLSVersion] : |
19+
| InsecureTLS.swift:158:7:158:7 | value : | file://:0:0:0:0 | value : |
20+
| InsecureTLS.swift:163:3:163:3 | [post] def [TLSVersion] : | InsecureTLS.swift:165:47:165:47 | def [TLSVersion] : |
21+
| InsecureTLS.swift:163:20:163:43 | .TLSv10 : | InsecureTLS.swift:158:7:158:7 | value : |
22+
| InsecureTLS.swift:163:20:163:43 | .TLSv10 : | InsecureTLS.swift:163:3:163:3 | [post] def [TLSVersion] : |
23+
| InsecureTLS.swift:165:47:165:47 | def [TLSVersion] : | InsecureTLS.swift:158:7:158:7 | self [TLSVersion] : |
24+
| InsecureTLS.swift:165:47:165:47 | def [TLSVersion] : | InsecureTLS.swift:165:47:165:51 | .TLSVersion |
25+
| InsecureTLS.swift:165:47:165:47 | def [TLSVersion] : | InsecureTLS.swift:165:47:165:51 | .TLSVersion : |
26+
| InsecureTLS.swift:165:47:165:51 | .TLSVersion : | InsecureTLS.swift:19:7:19:7 | value : |
27+
| file://:0:0:0:0 | self [TLSVersion] : | file://:0:0:0:0 | .TLSVersion : |
28+
| file://:0:0:0:0 | value : | file://:0:0:0:0 | [post] self [TLSVersion] : |
29+
nodes
30+
| InsecureTLS.swift:19:7:19:7 | value : | semmle.label | value : |
31+
| InsecureTLS.swift:20:7:20:7 | value : | semmle.label | value : |
32+
| InsecureTLS.swift:22:7:22:7 | value : | semmle.label | value : |
33+
| InsecureTLS.swift:23:7:23:7 | value : | semmle.label | value : |
34+
| InsecureTLS.swift:40:47:40:70 | .TLSv10 | semmle.label | .TLSv10 |
35+
| InsecureTLS.swift:40:47:40:70 | .TLSv10 : | semmle.label | .TLSv10 : |
36+
| InsecureTLS.swift:45:47:45:70 | .TLSv11 | semmle.label | .TLSv11 |
37+
| InsecureTLS.swift:45:47:45:70 | .TLSv11 : | semmle.label | .TLSv11 : |
38+
| InsecureTLS.swift:57:47:57:70 | .TLSv10 | semmle.label | .TLSv10 |
39+
| InsecureTLS.swift:57:47:57:70 | .TLSv10 : | semmle.label | .TLSv10 : |
40+
| InsecureTLS.swift:64:40:64:52 | .tlsProtocol10 | semmle.label | .tlsProtocol10 |
41+
| InsecureTLS.swift:64:40:64:52 | .tlsProtocol10 : | semmle.label | .tlsProtocol10 : |
42+
| InsecureTLS.swift:76:40:76:52 | .tlsProtocol10 | semmle.label | .tlsProtocol10 |
43+
| InsecureTLS.swift:76:40:76:52 | .tlsProtocol10 : | semmle.label | .tlsProtocol10 : |
44+
| InsecureTLS.swift:102:10:102:33 | .TLSv10 : | semmle.label | .TLSv10 : |
45+
| InsecureTLS.swift:111:47:111:64 | call to getBadTLSVersion() | semmle.label | call to getBadTLSVersion() |
46+
| InsecureTLS.swift:111:47:111:64 | call to getBadTLSVersion() : | semmle.label | call to getBadTLSVersion() : |
47+
| InsecureTLS.swift:121:55:121:66 | version : | semmle.label | version : |
48+
| InsecureTLS.swift:122:47:122:47 | version | semmle.label | version |
49+
| InsecureTLS.swift:122:47:122:47 | version : | semmle.label | version : |
50+
| InsecureTLS.swift:127:25:127:48 | .TLSv11 : | semmle.label | .TLSv11 : |
51+
| InsecureTLS.swift:158:7:158:7 | self [TLSVersion] : | semmle.label | self [TLSVersion] : |
52+
| InsecureTLS.swift:158:7:158:7 | value : | semmle.label | value : |
53+
| InsecureTLS.swift:163:3:163:3 | [post] def [TLSVersion] : | semmle.label | [post] def [TLSVersion] : |
54+
| InsecureTLS.swift:163:20:163:43 | .TLSv10 : | semmle.label | .TLSv10 : |
55+
| InsecureTLS.swift:165:47:165:47 | def [TLSVersion] : | semmle.label | def [TLSVersion] : |
56+
| InsecureTLS.swift:165:47:165:51 | .TLSVersion | semmle.label | .TLSVersion |
57+
| InsecureTLS.swift:165:47:165:51 | .TLSVersion : | semmle.label | .TLSVersion : |
58+
| file://:0:0:0:0 | .TLSVersion : | semmle.label | .TLSVersion : |
59+
| file://:0:0:0:0 | [post] self [TLSVersion] : | semmle.label | [post] self [TLSVersion] : |
60+
| file://:0:0:0:0 | self [TLSVersion] : | semmle.label | self [TLSVersion] : |
61+
| file://:0:0:0:0 | value | semmle.label | value |
62+
| file://:0:0:0:0 | value | semmle.label | value |
63+
| file://:0:0:0:0 | value | semmle.label | value |
64+
| file://:0:0:0:0 | value | semmle.label | value |
65+
| file://:0:0:0:0 | value : | semmle.label | value : |
66+
subpaths
67+
| InsecureTLS.swift:163:20:163:43 | .TLSv10 : | InsecureTLS.swift:158:7:158:7 | value : | file://:0:0:0:0 | [post] self [TLSVersion] : | InsecureTLS.swift:163:3:163:3 | [post] def [TLSVersion] : |
68+
| InsecureTLS.swift:165:47:165:47 | def [TLSVersion] : | InsecureTLS.swift:158:7:158:7 | self [TLSVersion] : | file://:0:0:0:0 | .TLSVersion : | InsecureTLS.swift:165:47:165:51 | .TLSVersion |
69+
| InsecureTLS.swift:165:47:165:47 | def [TLSVersion] : | InsecureTLS.swift:158:7:158:7 | self [TLSVersion] : | file://:0:0:0:0 | .TLSVersion : | InsecureTLS.swift:165:47:165:51 | .TLSVersion : |
70+
#select
71+
| InsecureTLS.swift:40:47:40:70 | .TLSv10 | InsecureTLS.swift:40:47:40:70 | .TLSv10 | InsecureTLS.swift:40:47:40:70 | .TLSv10 | This TLS configuration is insecure. |
72+
| InsecureTLS.swift:45:47:45:70 | .TLSv11 | InsecureTLS.swift:45:47:45:70 | .TLSv11 | InsecureTLS.swift:45:47:45:70 | .TLSv11 | This TLS configuration is insecure. |
73+
| InsecureTLS.swift:57:47:57:70 | .TLSv10 | InsecureTLS.swift:57:47:57:70 | .TLSv10 | InsecureTLS.swift:57:47:57:70 | .TLSv10 | This TLS configuration is insecure. |
74+
| InsecureTLS.swift:64:40:64:52 | .tlsProtocol10 | InsecureTLS.swift:64:40:64:52 | .tlsProtocol10 | InsecureTLS.swift:64:40:64:52 | .tlsProtocol10 | This TLS configuration is insecure. |
75+
| InsecureTLS.swift:76:40:76:52 | .tlsProtocol10 | InsecureTLS.swift:76:40:76:52 | .tlsProtocol10 | InsecureTLS.swift:76:40:76:52 | .tlsProtocol10 | This TLS configuration is insecure. |
76+
| InsecureTLS.swift:111:47:111:64 | call to getBadTLSVersion() | InsecureTLS.swift:102:10:102:33 | .TLSv10 : | InsecureTLS.swift:111:47:111:64 | call to getBadTLSVersion() | This TLS configuration is insecure. |
77+
| InsecureTLS.swift:122:47:122:47 | version | InsecureTLS.swift:127:25:127:48 | .TLSv11 : | InsecureTLS.swift:122:47:122:47 | version | This TLS configuration is insecure. |
78+
| InsecureTLS.swift:165:47:165:51 | .TLSVersion | InsecureTLS.swift:163:20:163:43 | .TLSv10 : | InsecureTLS.swift:165:47:165:51 | .TLSVersion | This TLS configuration is insecure. |
79+
| file://:0:0:0:0 | value | InsecureTLS.swift:40:47:40:70 | .TLSv10 : | file://:0:0:0:0 | value | This TLS configuration is insecure. |
80+
| file://:0:0:0:0 | value | InsecureTLS.swift:45:47:45:70 | .TLSv11 : | file://:0:0:0:0 | value | This TLS configuration is insecure. |
81+
| file://:0:0:0:0 | value | InsecureTLS.swift:57:47:57:70 | .TLSv10 : | file://:0:0:0:0 | value | This TLS configuration is insecure. |
82+
| file://:0:0:0:0 | value | InsecureTLS.swift:64:40:64:52 | .tlsProtocol10 : | file://:0:0:0:0 | value | This TLS configuration is insecure. |
83+
| file://:0:0:0:0 | value | InsecureTLS.swift:76:40:76:52 | .tlsProtocol10 : | file://:0:0:0:0 | value | This TLS configuration is insecure. |
84+
| file://:0:0:0:0 | value | InsecureTLS.swift:102:10:102:33 | .TLSv10 : | file://:0:0:0:0 | value | This TLS configuration is insecure. |
85+
| file://:0:0:0:0 | value | InsecureTLS.swift:127:25:127:48 | .TLSv11 : | file://:0:0:0:0 | value | This TLS configuration is insecure. |
86+
| file://:0:0:0:0 | value | InsecureTLS.swift:163:20:163:43 | .TLSv10 : | file://:0:0:0:0 | value | This TLS configuration is insecure. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
queries/Security/CWE-757/InsecureTLS.ql
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
// Stubs
2+
3+
enum tls_protocol_version_t : UInt16 {
4+
case TLSv10
5+
case TLSv11
6+
case TLSv12
7+
case TLSv13
8+
}
9+
10+
enum SSLProtocol {
11+
case tlsProtocol10
12+
case tlsProtocol11
13+
case tlsProtocol12
14+
case tlsProtocol13
15+
}
16+
17+
class URLSessionConfiguration {
18+
init() {}
19+
var tlsMinimumSupportedProtocolVersion: tls_protocol_version_t = tls_protocol_version_t.TLSv12
20+
var tlsMaximumSupportedProtocolVersion: tls_protocol_version_t = tls_protocol_version_t.TLSv13
21+
22+
var tlsMinimumSupportedProtocol: SSLProtocol = SSLProtocol.tlsProtocol12
23+
var tlsMaximumSupportedProtocol: SSLProtocol = SSLProtocol.tlsProtocol13
24+
}
25+
26+
/// tlsMinimumSupportedProtocolVersion
27+
28+
func case_0() {
29+
let config = URLSessionConfiguration()
30+
config.tlsMinimumSupportedProtocolVersion = tls_protocol_version_t.TLSv12 // GOOD
31+
}
32+
33+
func case_1() {
34+
let config = URLSessionConfiguration()
35+
config.tlsMinimumSupportedProtocolVersion = tls_protocol_version_t.TLSv13 // GOOD
36+
}
37+
38+
func case_2() {
39+
let config = URLSessionConfiguration()
40+
config.tlsMinimumSupportedProtocolVersion = tls_protocol_version_t.TLSv10 // BAD
41+
}
42+
43+
func case_3() {
44+
let config = URLSessionConfiguration()
45+
config.tlsMinimumSupportedProtocolVersion = tls_protocol_version_t.TLSv11 // BAD
46+
}
47+
48+
/// tlsMaximumSupportedProtocolVersion
49+
50+
func case_4() {
51+
let config = URLSessionConfiguration()
52+
config.tlsMaximumSupportedProtocolVersion = tls_protocol_version_t.TLSv12 // GOOD
53+
}
54+
55+
func case_5() {
56+
let config = URLSessionConfiguration()
57+
config.tlsMaximumSupportedProtocolVersion = tls_protocol_version_t.TLSv10 // BAD
58+
}
59+
60+
/// tlsMinimumSupportedProtocol
61+
62+
func case_6() {
63+
let config = URLSessionConfiguration()
64+
config.tlsMinimumSupportedProtocol = SSLProtocol.tlsProtocol10 // BAD
65+
}
66+
67+
func case_7() {
68+
let config = URLSessionConfiguration()
69+
config.tlsMinimumSupportedProtocol = SSLProtocol.tlsProtocol12 // GOOD
70+
}
71+
72+
/// tlsMaximumSupportedProtocol
73+
74+
func case_8() {
75+
let config = URLSessionConfiguration()
76+
config.tlsMaximumSupportedProtocol = SSLProtocol.tlsProtocol10 // BAD
77+
}
78+
79+
func case_9() {
80+
let config = URLSessionConfiguration()
81+
config.tlsMaximumSupportedProtocol = SSLProtocol.tlsProtocol12 // GOOD
82+
}
83+
84+
/// Indirect assignment (global vars)
85+
86+
let badGlobalVersion = tls_protocol_version_t.TLSv10
87+
let goodGlobalVersion = tls_protocol_version_t.TLSv12
88+
89+
func case_10() {
90+
let config = URLSessionConfiguration()
91+
config.tlsMinimumSupportedProtocolVersion = badGlobalVersion // BAD [not detected]
92+
}
93+
94+
func case_11() {
95+
let config = URLSessionConfiguration()
96+
config.tlsMinimumSupportedProtocolVersion = goodGlobalVersion // GOOD
97+
}
98+
99+
/// Indirect assignment (function calls)
100+
101+
func getBadTLSVersion() -> tls_protocol_version_t {
102+
return tls_protocol_version_t.TLSv10
103+
}
104+
105+
func getGoodTLSVersion() -> tls_protocol_version_t {
106+
return tls_protocol_version_t.TLSv13
107+
}
108+
109+
func case_12() {
110+
let config = URLSessionConfiguration()
111+
config.tlsMinimumSupportedProtocolVersion = getBadTLSVersion() // BAD
112+
}
113+
114+
func case_13() {
115+
let config = URLSessionConfiguration()
116+
config.tlsMinimumSupportedProtocolVersion = getGoodTLSVersion() // GOOD
117+
}
118+
119+
/// Indirect assignment (via call arguments)
120+
121+
func setTLSVersion(_ config: URLSessionConfiguration, _ version: tls_protocol_version_t) {
122+
config.tlsMinimumSupportedProtocolVersion = version
123+
}
124+
125+
func case_14() {
126+
let config = URLSessionConfiguration()
127+
setTLSVersion(config, tls_protocol_version_t.TLSv11) // BAD
128+
}
129+
130+
func case_15() {
131+
let config = URLSessionConfiguration()
132+
setTLSVersion(config, tls_protocol_version_t.TLSv13) // GOOD
133+
}
134+
135+
/// Indirect assignment (via external entity)
136+
137+
struct BadDefault {
138+
let TLSVersion: tls_protocol_version_t = tls_protocol_version_t.TLSv11
139+
}
140+
141+
func case_16() {
142+
let def = BadDefault()
143+
let config = URLSessionConfiguration()
144+
config.tlsMinimumSupportedProtocolVersion = def.TLSVersion // BAD [not detected]
145+
}
146+
147+
struct GoodDefault {
148+
let TLSVersion: tls_protocol_version_t = tls_protocol_version_t.TLSv12
149+
}
150+
151+
func case_17() {
152+
let def = GoodDefault()
153+
let config = URLSessionConfiguration()
154+
config.tlsMinimumSupportedProtocolVersion = def.TLSVersion // GOOD
155+
}
156+
157+
struct VarDefault {
158+
var TLSVersion: tls_protocol_version_t = tls_protocol_version_t.TLSv12
159+
}
160+
161+
func case_18() {
162+
var def = VarDefault()
163+
def.TLSVersion = tls_protocol_version_t.TLSv10
164+
let config = URLSessionConfiguration()
165+
config.tlsMinimumSupportedProtocolVersion = def.TLSVersion // BAD
166+
}
167+
168+
func case_19() {
169+
var def = VarDefault()
170+
def.TLSVersion = tls_protocol_version_t.TLSv13
171+
let config = URLSessionConfiguration()
172+
config.tlsMinimumSupportedProtocolVersion = def.TLSVersion // GOOD
173+
}

0 commit comments

Comments
 (0)