Skip to content

Commit e62a6a0

Browse files
committed
Swift: Split encryption queries into three parts (trivial re-organization of existing code).
1 parent f5a2853 commit e62a6a0

24 files changed

+498
-383
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/**
2+
* Provides classes and predicates for reasoning about constant password
3+
* vulnerabilities.
4+
*/
5+
6+
import swift
7+
import codeql.swift.dataflow.DataFlow
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* Provides a taint tracking configuration to find constant password
3+
* vulnerabilities.
4+
*/
5+
6+
import swift
7+
import codeql.swift.dataflow.DataFlow
8+
import codeql.swift.dataflow.TaintTracking
9+
import codeql.swift.dataflow.FlowSteps
10+
import codeql.swift.security.ConstantPasswordExtensions
11+
12+
/**
13+
* A constant password is created through either a byte array or string literals.
14+
*/
15+
class ConstantPasswordSource extends Expr {
16+
ConstantPasswordSource() {
17+
this = any(ArrayExpr arr | arr.getType().getName() = "Array<UInt8>") or
18+
this instanceof StringLiteralExpr
19+
}
20+
}
21+
22+
/**
23+
* A class for all ways to use a constant password.
24+
*/
25+
class ConstantPasswordSink extends Expr {
26+
ConstantPasswordSink() {
27+
// `password` arg in `init` is a sink
28+
exists(ClassOrStructDecl c, ConstructorDecl f, CallExpr call |
29+
c.getName() = ["HKDF", "PBKDF1", "PBKDF2", "Scrypt"] and
30+
c.getAMember() = f and
31+
call.getStaticTarget() = f and
32+
call.getArgumentWithLabel("password").getExpr() = this
33+
)
34+
or
35+
// RNCryptor (labelled arguments)
36+
exists(ClassOrStructDecl c, MethodDecl f, CallExpr call |
37+
c.getName() = ["RNCryptor", "RNEncryptor", "RNDecryptor"] and
38+
c.getAMember() = f and
39+
call.getStaticTarget() = f and
40+
call.getArgumentWithLabel(["password", "withPassword", "forPassword"]).getExpr() = this
41+
)
42+
or
43+
// RNCryptor (unlabelled arguments)
44+
exists(MethodDecl f, CallExpr call |
45+
f.hasQualifiedName("RNCryptor", "keyForPassword(_:salt:settings:)") and
46+
call.getStaticTarget() = f and
47+
call.getArgument(0).getExpr() = this
48+
)
49+
}
50+
}
51+
52+
/**
53+
* A taint configuration from the source of constants passwords to expressions that use
54+
* them to initialize password-based encryption keys.
55+
*/
56+
module ConstantPasswordConfig implements DataFlow::ConfigSig {
57+
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof ConstantPasswordSource }
58+
59+
predicate isSink(DataFlow::Node node) { node.asExpr() instanceof ConstantPasswordSink }
60+
}
61+
62+
module ConstantPasswordFlow = TaintTracking::Global<ConstantPasswordConfig>;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/**
2+
* Provides classes and predicates for reasoning about use of constant salts
3+
* for password hashing.
4+
*/
5+
6+
import swift
7+
import codeql.swift.dataflow.DataFlow
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* Provides a taint tracking configuration to find use of constant salts
3+
* for password hashing.
4+
*/
5+
6+
import swift
7+
import codeql.swift.dataflow.DataFlow
8+
import codeql.swift.dataflow.TaintTracking
9+
import codeql.swift.dataflow.FlowSteps
10+
import codeql.swift.security.ConstantSaltExtensions
11+
12+
/**
13+
* A constant salt is created through either a byte array or string literals.
14+
*/
15+
class ConstantSaltSource extends Expr {
16+
ConstantSaltSource() {
17+
this = any(ArrayExpr arr | arr.getType().getName() = "Array<UInt8>") or
18+
this instanceof StringLiteralExpr or
19+
this instanceof NumberLiteralExpr
20+
}
21+
}
22+
23+
/**
24+
* A class for all ways to use a constant salt.
25+
*/
26+
class ConstantSaltSink extends Expr {
27+
ConstantSaltSink() {
28+
// `salt` arg in `init` is a sink
29+
exists(ClassOrStructDecl c, ConstructorDecl f, CallExpr call |
30+
c.getName() = ["HKDF", "PBKDF1", "PBKDF2", "Scrypt"] and
31+
c.getAMember() = f and
32+
call.getStaticTarget() = f and
33+
call.getArgumentWithLabel("salt").getExpr() = this
34+
)
35+
or
36+
// RNCryptor
37+
exists(ClassOrStructDecl c, MethodDecl f, CallExpr call |
38+
c.getName() = ["RNCryptor", "RNEncryptor", "RNDecryptor"] and
39+
c.getAMember() = f and
40+
call.getStaticTarget() = f and
41+
call.getArgumentWithLabel(["salt", "encryptionSalt", "hmacSalt", "HMACSalt"]).getExpr() = this
42+
)
43+
}
44+
}
45+
46+
/**
47+
* A taint configuration from the source of constants salts to expressions that use
48+
* them to initialize password-based encryption keys.
49+
*/
50+
module ConstantSaltConfig implements DataFlow::ConfigSig {
51+
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof ConstantSaltSource }
52+
53+
predicate isSink(DataFlow::Node node) { node.asExpr() instanceof ConstantSaltSink }
54+
}
55+
56+
module ConstantSaltFlow = TaintTracking::Global<ConstantSaltConfig>;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/**
2+
* Provides classes and predicates for reasoning about encryption using the
3+
* ECB encrpytion mode.
4+
*/
5+
6+
import swift
7+
import codeql.swift.dataflow.DataFlow
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* Provides a taint tracking configuration to find encryption using the
3+
* ECB encrpytion mode.
4+
*/
5+
6+
import swift
7+
import codeql.swift.dataflow.DataFlow
8+
import codeql.swift.dataflow.TaintTracking
9+
import codeql.swift.security.ECBEncryptionExtensions
10+
11+
/**
12+
* An `Expr` that is used to initialize the block mode of a cipher.
13+
*/
14+
abstract class BlockMode extends Expr { }
15+
16+
/**
17+
* An `Expr` that is used to form an `AES` cipher.
18+
*/
19+
class AES extends BlockMode {
20+
AES() {
21+
// `blockMode` arg in `AES.init` is a sink
22+
exists(CallExpr call |
23+
call.getStaticTarget()
24+
.(MethodDecl)
25+
.hasQualifiedName("AES", ["init(key:blockMode:)", "init(key:blockMode:padding:)"]) and
26+
call.getArgument(1).getExpr() = this
27+
)
28+
}
29+
}
30+
31+
/**
32+
* An `Expr` that is used to form a `Blowfish` cipher.
33+
*/
34+
class Blowfish extends BlockMode {
35+
Blowfish() {
36+
// `blockMode` arg in `Blowfish.init` is a sink
37+
exists(CallExpr call |
38+
call.getStaticTarget()
39+
.(MethodDecl)
40+
.hasQualifiedName("Blowfish", "init(key:blockMode:padding:)") and
41+
call.getArgument(1).getExpr() = this
42+
)
43+
}
44+
}
45+
46+
/**
47+
* A taint configuration from the constructor of ECB mode to expressions that use
48+
* it to initialize a cipher.
49+
*/
50+
module EcbEncryptionConfig implements DataFlow::ConfigSig {
51+
predicate isSource(DataFlow::Node node) {
52+
exists(CallExpr call |
53+
call.getStaticTarget().(MethodDecl).hasQualifiedName("ECB", "init()") and
54+
node.asExpr() = call
55+
)
56+
}
57+
58+
predicate isSink(DataFlow::Node node) { node.asExpr() instanceof BlockMode }
59+
}
60+
61+
module EcbEncryptionFlow = DataFlow::Global<EcbEncryptionConfig>;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/**
2+
* Provides classes and predicates for reasoning about hard-coded encryption
3+
* key vulnerabilities.
4+
*/
5+
6+
import swift
7+
import codeql.swift.dataflow.DataFlow
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* Provides a taint tracking configuration to find hard-coded encryption
3+
* key vulnerabilities.
4+
*/
5+
6+
import swift
7+
import codeql.swift.dataflow.DataFlow
8+
import codeql.swift.dataflow.TaintTracking
9+
import codeql.swift.security.HardcodedEncryptionKeyExtensions
10+
11+
/**
12+
* An `Expr` that is used to initialize a key.
13+
*/
14+
abstract class KeySource extends Expr { }
15+
16+
/**
17+
* A literal byte array is a key source.
18+
*/
19+
class ByteArrayLiteralSource extends KeySource {
20+
ByteArrayLiteralSource() { this = any(ArrayExpr arr | arr.getType().getName() = "Array<UInt8>") }
21+
}
22+
23+
/**
24+
* A string literal is a key source.
25+
*/
26+
class StringLiteralSource extends KeySource instanceof StringLiteralExpr { }
27+
28+
/**
29+
* A class for all ways to set a key.
30+
*/
31+
class EncryptionKeySink extends Expr {
32+
EncryptionKeySink() {
33+
// `key` arg in `init` is a sink
34+
exists(CallExpr call, string fName |
35+
call.getStaticTarget()
36+
.(MethodDecl)
37+
.hasQualifiedName([
38+
"AES", "HMAC", "ChaCha20", "CBCMAC", "CMAC", "Poly1305", "Blowfish", "Rabbit"
39+
], fName) and
40+
fName.matches("init(key:%") and
41+
call.getArgument(0).getExpr() = this
42+
)
43+
or
44+
// RNCryptor
45+
exists(ClassOrStructDecl c, MethodDecl f, CallExpr call |
46+
c.getFullName() = ["RNCryptor", "RNEncryptor", "RNDecryptor"] and
47+
c.getAMember() = f and
48+
call.getStaticTarget() = f and
49+
call.getArgumentWithLabel(["encryptionKey", "withEncryptionKey"]).getExpr() = this
50+
)
51+
}
52+
}
53+
54+
/**
55+
* A taint configuration from the key source to expressions that use
56+
* it to initialize a cipher.
57+
*/
58+
module HardcodedKeyConfig implements DataFlow::ConfigSig {
59+
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof KeySource }
60+
61+
predicate isSink(DataFlow::Node node) { node.asExpr() instanceof EncryptionKeySink }
62+
}
63+
64+
module HardcodedKeyFlow = TaintTracking::Global<HardcodedKeyConfig>;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/**
2+
* Provides classes and predicates for reasoning about insecure TLS
3+
* configurations.
4+
*/
5+
6+
import swift
7+
import codeql.swift.dataflow.DataFlow
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Provides a taint tracking configuration to find insecure TLS
3+
* configurations.
4+
*/
5+
6+
import swift
7+
import codeql.swift.dataflow.DataFlow
8+
import codeql.swift.dataflow.TaintTracking
9+
import codeql.swift.dataflow.FlowSources
10+
import codeql.swift.security.InsecureTLSExtensions
11+
12+
/**
13+
* A taint config to detect insecure configuration of `NSURLSessionConfiguration`
14+
*/
15+
module InsecureTlsConfig implements DataFlow::ConfigSig {
16+
/**
17+
* Holds for enum values that represent an insecure version of TLS
18+
*/
19+
predicate isSource(DataFlow::Node node) {
20+
node.asExpr().(MethodLookupExpr).getMember().(EnumElementDecl).getName() =
21+
["TLSv10", "TLSv11", "tlsProtocol10", "tlsProtocol11"]
22+
}
23+
24+
/**
25+
* Holds for assignment of TLS-related properties of `NSURLSessionConfiguration`
26+
*/
27+
predicate isSink(DataFlow::Node node) {
28+
exists(AssignExpr assign |
29+
assign.getSource() = node.asExpr() and
30+
assign.getDest().(MemberRefExpr).getMember().(ConcreteVarDecl).getName() =
31+
[
32+
"tlsMinimumSupportedProtocolVersion", "tlsMinimumSupportedProtocol",
33+
"tlsMaximumSupportedProtocolVersion", "tlsMaximumSupportedProtocol"
34+
]
35+
)
36+
}
37+
}
38+
39+
module InsecureTlsFlow = TaintTracking::Global<InsecureTlsConfig>;

0 commit comments

Comments
 (0)