Skip to content

Commit fc5e958

Browse files
committed
Swift: Add extendible sinks, sanitizers etc and use them.
1 parent e62a6a0 commit fc5e958

17 files changed

+452
-198
lines changed

swift/ql/lib/codeql/swift/security/ConstantPasswordExtensions.qll

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,62 @@
55

66
import swift
77
import codeql.swift.dataflow.DataFlow
8+
9+
/**
10+
* A dataflow sink for constant password vulnerabilities. That is,
11+
* a `DataFlow::Node` of something that is used as a password.
12+
*/
13+
abstract class ConstantPasswordSink extends DataFlow::Node { }
14+
15+
/**
16+
* A sanitizer for constant password vulnerabilities.
17+
*/
18+
abstract class ConstantPasswordSanitizer extends DataFlow::Node { }
19+
20+
/**
21+
* A unit class for adding additional taint steps.
22+
*/
23+
class ConstantPasswordAdditionalTaintStep extends Unit {
24+
/**
25+
* Holds if the step from `node1` to `node2` should be considered a taint
26+
* step for paths related to constant password vulnerabilities.
27+
*/
28+
abstract predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo);
29+
}
30+
31+
/**
32+
* A password sink for the CryptoSwift library.
33+
*/
34+
private class DefaultConstantPasswordSink extends ConstantPasswordSink {
35+
DefaultConstantPasswordSink() {
36+
// `password` arg in `init` is a sink
37+
exists(ClassOrStructDecl c, ConstructorDecl f, CallExpr call |
38+
c.getName() = ["HKDF", "PBKDF1", "PBKDF2", "Scrypt"] and
39+
c.getAMember() = f and
40+
call.getStaticTarget() = f and
41+
call.getArgumentWithLabel("password").getExpr() = this.asExpr()
42+
)
43+
}
44+
}
45+
46+
/**
47+
* A password sink for the RNCryptor library.
48+
*/
49+
private class RnCryptorPasswordSink extends ConstantPasswordSink {
50+
RnCryptorPasswordSink() {
51+
// RNCryptor (labelled arguments)
52+
exists(ClassOrStructDecl c, MethodDecl f, CallExpr call |
53+
c.getName() = ["RNCryptor", "RNEncryptor", "RNDecryptor"] and
54+
c.getAMember() = f and
55+
call.getStaticTarget() = f and
56+
call.getArgumentWithLabel(["password", "withPassword", "forPassword"]).getExpr() = this.asExpr()
57+
)
58+
or
59+
// RNCryptor (unlabelled arguments)
60+
exists(MethodDecl f, CallExpr call |
61+
f.hasQualifiedName("RNCryptor", "keyForPassword(_:salt:settings:)") and
62+
call.getStaticTarget() = f and
63+
call.getArgument(0).getExpr() = this.asExpr()
64+
)
65+
}
66+
}

swift/ql/lib/codeql/swift/security/ConstantPasswordQuery.qll

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,44 +19,20 @@ class ConstantPasswordSource extends Expr {
1919
}
2020
}
2121

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-
5222
/**
5323
* A taint configuration from the source of constants passwords to expressions that use
5424
* them to initialize password-based encryption keys.
5525
*/
5626
module ConstantPasswordConfig implements DataFlow::ConfigSig {
5727
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof ConstantPasswordSource }
5828

59-
predicate isSink(DataFlow::Node node) { node.asExpr() instanceof ConstantPasswordSink }
29+
predicate isSink(DataFlow::Node node) { node instanceof ConstantPasswordSink }
30+
31+
predicate isBarrier(DataFlow::Node node) { node instanceof ConstantPasswordSanitizer}
32+
33+
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
34+
any(ConstantPasswordAdditionalTaintStep s).step(nodeFrom, nodeTo)
35+
}
6036
}
6137

6238
module ConstantPasswordFlow = TaintTracking::Global<ConstantPasswordConfig>;

swift/ql/lib/codeql/swift/security/ConstantSaltExtensions.qll

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,55 @@
55

66
import swift
77
import codeql.swift.dataflow.DataFlow
8+
9+
/**
10+
* A dataflow sink for constant salt vulnerabilities. That is,
11+
* a `DataFlow::Node` of something that is used as a salt.
12+
*/
13+
abstract class ConstantSaltSink extends DataFlow::Node { }
14+
15+
/**
16+
* A sanitizer for constant salt vulnerabilities.
17+
*/
18+
abstract class ConstantSaltSanitizer extends DataFlow::Node { }
19+
20+
/**
21+
* A unit class for adding additional taint steps.
22+
*/
23+
class ConstantSaltAdditionalTaintStep extends Unit {
24+
/**
25+
* Holds if the step from `node1` to `node2` should be considered a taint
26+
* step for paths related to constant salt vulnerabilities.
27+
*/
28+
abstract predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo);
29+
}
30+
31+
32+
/**
33+
* A sink for the CryptoSwift library.
34+
*/
35+
private class CryptoSwiftSaltSink extends ConstantSaltSink {
36+
CryptoSwiftSaltSink() {
37+
// `salt` arg in `init` is a sink
38+
exists(ClassOrStructDecl c, ConstructorDecl f, CallExpr call |
39+
c.getName() = ["HKDF", "PBKDF1", "PBKDF2", "Scrypt"] and
40+
c.getAMember() = f and
41+
call.getStaticTarget() = f and
42+
call.getArgumentWithLabel("salt").getExpr() = this.asExpr()
43+
)
44+
}
45+
}
46+
47+
/**
48+
* A sink for the RNCryptor library.
49+
*/
50+
private class RnCryptorSaltSink extends ConstantSaltSink {
51+
RnCryptorSaltSink() {
52+
exists(ClassOrStructDecl c, MethodDecl f, CallExpr call |
53+
c.getName() = ["RNCryptor", "RNEncryptor", "RNDecryptor"] and
54+
c.getAMember() = f and
55+
call.getStaticTarget() = f and
56+
call.getArgumentWithLabel(["salt", "encryptionSalt", "hmacSalt", "HMACSalt"]).getExpr() = this.asExpr()
57+
)
58+
}
59+
}

swift/ql/lib/codeql/swift/security/ConstantSaltQuery.qll

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,37 +20,20 @@ class ConstantSaltSource extends Expr {
2020
}
2121
}
2222

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-
4623
/**
4724
* A taint configuration from the source of constants salts to expressions that use
4825
* them to initialize password-based encryption keys.
4926
*/
5027
module ConstantSaltConfig implements DataFlow::ConfigSig {
5128
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof ConstantSaltSource }
5229

53-
predicate isSink(DataFlow::Node node) { node.asExpr() instanceof ConstantSaltSink }
30+
predicate isSink(DataFlow::Node node) { node instanceof ConstantSaltSink }
31+
32+
predicate isBarrier(DataFlow::Node node) { node instanceof ConstantSaltSanitizer}
33+
34+
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
35+
any(ConstantSaltAdditionalTaintStep s).step(nodeFrom, nodeTo)
36+
}
5437
}
5538

5639
module ConstantSaltFlow = TaintTracking::Global<ConstantSaltConfig>;
Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,60 @@
11
/**
22
* Provides classes and predicates for reasoning about encryption using the
3-
* ECB encrpytion mode.
3+
* ECB encryption mode.
44
*/
55

66
import swift
77
import codeql.swift.dataflow.DataFlow
8+
9+
/**
10+
* A dataflow sink for ECB encryption vulnerabilities. That is,
11+
* a `DataFlow::Node` of something that is used as the block mode
12+
* of a cipher.
13+
*/
14+
abstract class EcbEncryptionSink extends DataFlow::Node { }
15+
16+
/**
17+
* A sanitizer for ECB encryption vulnerabilities.
18+
*/
19+
abstract class EcbEncryptionSanitizer extends DataFlow::Node { }
20+
21+
/**
22+
* A unit class for adding additional taint steps.
23+
*/
24+
class EcbEncryptionAdditionalTaintStep extends Unit {
25+
/**
26+
* Holds if the step from `node1` to `node2` should be considered a taint
27+
* step for paths related to ECB encryption vulnerabilities.
28+
*/
29+
abstract predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo);
30+
}
31+
32+
/**
33+
* A block mode being used to form an `AES` cipher.
34+
*/
35+
private class AES extends EcbEncryptionSink {
36+
AES() {
37+
// `blockMode` arg in `AES.init` is a sink
38+
exists(CallExpr call |
39+
call.getStaticTarget()
40+
.(MethodDecl)
41+
.hasQualifiedName("AES", ["init(key:blockMode:)", "init(key:blockMode:padding:)"]) and
42+
call.getArgument(1).getExpr() = this.asExpr()
43+
)
44+
}
45+
}
46+
47+
/**
48+
* A block mode being used to form a `Blowfish` cipher.
49+
*/
50+
private class Blowfish extends EcbEncryptionSink {
51+
Blowfish() {
52+
// `blockMode` arg in `Blowfish.init` is a sink
53+
exists(CallExpr call |
54+
call.getStaticTarget()
55+
.(MethodDecl)
56+
.hasQualifiedName("Blowfish", "init(key:blockMode:padding:)") and
57+
call.getArgument(1).getExpr() = this.asExpr()
58+
)
59+
}
60+
}
Lines changed: 8 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,13 @@
11
/**
22
* Provides a taint tracking configuration to find encryption using the
3-
* ECB encrpytion mode.
3+
* ECB encryption mode.
44
*/
55

66
import swift
77
import codeql.swift.dataflow.DataFlow
88
import codeql.swift.dataflow.TaintTracking
99
import codeql.swift.security.ECBEncryptionExtensions
1010

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-
4611
/**
4712
* A taint configuration from the constructor of ECB mode to expressions that use
4813
* it to initialize a cipher.
@@ -55,7 +20,13 @@ module EcbEncryptionConfig implements DataFlow::ConfigSig {
5520
)
5621
}
5722

58-
predicate isSink(DataFlow::Node node) { node.asExpr() instanceof BlockMode }
23+
predicate isSink(DataFlow::Node node) { node instanceof EcbEncryptionSink }
24+
25+
predicate isBarrier(DataFlow::Node node) { node instanceof EcbEncryptionSanitizer}
26+
27+
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
28+
any(EcbEncryptionAdditionalTaintStep s).step(nodeFrom, nodeTo)
29+
}
5930
}
6031

6132
module EcbEncryptionFlow = DataFlow::Global<EcbEncryptionConfig>;

0 commit comments

Comments
 (0)