Swift: Split encryption queries into three parts (trivial re-organization of existing code).

This commit is contained in:
Geoffrey White
2023-04-03 16:22:22 +01:00
parent f5a2853ab9
commit e62a6a037c
24 changed files with 498 additions and 383 deletions

View File

@@ -0,0 +1,7 @@
/**
* Provides classes and predicates for reasoning about constant password
* vulnerabilities.
*/
import swift
import codeql.swift.dataflow.DataFlow

View File

@@ -0,0 +1,62 @@
/**
* Provides a taint tracking configuration to find constant password
* vulnerabilities.
*/
import swift
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.dataflow.FlowSteps
import codeql.swift.security.ConstantPasswordExtensions
/**
* A constant password is created through either a byte array or string literals.
*/
class ConstantPasswordSource extends Expr {
ConstantPasswordSource() {
this = any(ArrayExpr arr | arr.getType().getName() = "Array<UInt8>") or
this instanceof StringLiteralExpr
}
}
/**
* A class for all ways to use a constant password.
*/
class ConstantPasswordSink extends Expr {
ConstantPasswordSink() {
// `password` arg in `init` is a sink
exists(ClassOrStructDecl c, ConstructorDecl f, CallExpr call |
c.getName() = ["HKDF", "PBKDF1", "PBKDF2", "Scrypt"] and
c.getAMember() = f and
call.getStaticTarget() = f and
call.getArgumentWithLabel("password").getExpr() = this
)
or
// RNCryptor (labelled arguments)
exists(ClassOrStructDecl c, MethodDecl f, CallExpr call |
c.getName() = ["RNCryptor", "RNEncryptor", "RNDecryptor"] and
c.getAMember() = f and
call.getStaticTarget() = f and
call.getArgumentWithLabel(["password", "withPassword", "forPassword"]).getExpr() = this
)
or
// RNCryptor (unlabelled arguments)
exists(MethodDecl f, CallExpr call |
f.hasQualifiedName("RNCryptor", "keyForPassword(_:salt:settings:)") and
call.getStaticTarget() = f and
call.getArgument(0).getExpr() = this
)
}
}
/**
* A taint configuration from the source of constants passwords to expressions that use
* them to initialize password-based encryption keys.
*/
module ConstantPasswordConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof ConstantPasswordSource }
predicate isSink(DataFlow::Node node) { node.asExpr() instanceof ConstantPasswordSink }
}
module ConstantPasswordFlow = TaintTracking::Global<ConstantPasswordConfig>;

View File

@@ -0,0 +1,7 @@
/**
* Provides classes and predicates for reasoning about use of constant salts
* for password hashing.
*/
import swift
import codeql.swift.dataflow.DataFlow

View File

@@ -0,0 +1,56 @@
/**
* Provides a taint tracking configuration to find use of constant salts
* for password hashing.
*/
import swift
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.dataflow.FlowSteps
import codeql.swift.security.ConstantSaltExtensions
/**
* A constant salt is created through either a byte array or string literals.
*/
class ConstantSaltSource extends Expr {
ConstantSaltSource() {
this = any(ArrayExpr arr | arr.getType().getName() = "Array<UInt8>") or
this instanceof StringLiteralExpr or
this instanceof NumberLiteralExpr
}
}
/**
* A class for all ways to use a constant salt.
*/
class ConstantSaltSink extends Expr {
ConstantSaltSink() {
// `salt` arg in `init` is a sink
exists(ClassOrStructDecl c, ConstructorDecl f, CallExpr call |
c.getName() = ["HKDF", "PBKDF1", "PBKDF2", "Scrypt"] and
c.getAMember() = f and
call.getStaticTarget() = f and
call.getArgumentWithLabel("salt").getExpr() = this
)
or
// RNCryptor
exists(ClassOrStructDecl c, MethodDecl f, CallExpr call |
c.getName() = ["RNCryptor", "RNEncryptor", "RNDecryptor"] and
c.getAMember() = f and
call.getStaticTarget() = f and
call.getArgumentWithLabel(["salt", "encryptionSalt", "hmacSalt", "HMACSalt"]).getExpr() = this
)
}
}
/**
* A taint configuration from the source of constants salts to expressions that use
* them to initialize password-based encryption keys.
*/
module ConstantSaltConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof ConstantSaltSource }
predicate isSink(DataFlow::Node node) { node.asExpr() instanceof ConstantSaltSink }
}
module ConstantSaltFlow = TaintTracking::Global<ConstantSaltConfig>;

View File

@@ -0,0 +1,7 @@
/**
* Provides classes and predicates for reasoning about encryption using the
* ECB encrpytion mode.
*/
import swift
import codeql.swift.dataflow.DataFlow

View File

@@ -0,0 +1,61 @@
/**
* Provides a taint tracking configuration to find encryption using the
* ECB encrpytion mode.
*/
import swift
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.security.ECBEncryptionExtensions
/**
* An `Expr` that is used to initialize the block mode of a cipher.
*/
abstract class BlockMode extends Expr { }
/**
* An `Expr` that is used to form an `AES` cipher.
*/
class AES extends BlockMode {
AES() {
// `blockMode` arg in `AES.init` is a sink
exists(CallExpr call |
call.getStaticTarget()
.(MethodDecl)
.hasQualifiedName("AES", ["init(key:blockMode:)", "init(key:blockMode:padding:)"]) and
call.getArgument(1).getExpr() = this
)
}
}
/**
* An `Expr` that is used to form a `Blowfish` cipher.
*/
class Blowfish extends BlockMode {
Blowfish() {
// `blockMode` arg in `Blowfish.init` is a sink
exists(CallExpr call |
call.getStaticTarget()
.(MethodDecl)
.hasQualifiedName("Blowfish", "init(key:blockMode:padding:)") and
call.getArgument(1).getExpr() = this
)
}
}
/**
* A taint configuration from the constructor of ECB mode to expressions that use
* it to initialize a cipher.
*/
module EcbEncryptionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) {
exists(CallExpr call |
call.getStaticTarget().(MethodDecl).hasQualifiedName("ECB", "init()") and
node.asExpr() = call
)
}
predicate isSink(DataFlow::Node node) { node.asExpr() instanceof BlockMode }
}
module EcbEncryptionFlow = DataFlow::Global<EcbEncryptionConfig>;

View File

@@ -0,0 +1,7 @@
/**
* Provides classes and predicates for reasoning about hard-coded encryption
* key vulnerabilities.
*/
import swift
import codeql.swift.dataflow.DataFlow

View File

@@ -0,0 +1,64 @@
/**
* Provides a taint tracking configuration to find hard-coded encryption
* key vulnerabilities.
*/
import swift
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.security.HardcodedEncryptionKeyExtensions
/**
* An `Expr` that is used to initialize a key.
*/
abstract class KeySource extends Expr { }
/**
* A literal byte array is a key source.
*/
class ByteArrayLiteralSource extends KeySource {
ByteArrayLiteralSource() { this = any(ArrayExpr arr | arr.getType().getName() = "Array<UInt8>") }
}
/**
* A string literal is a key source.
*/
class StringLiteralSource extends KeySource instanceof StringLiteralExpr { }
/**
* A class for all ways to set a key.
*/
class EncryptionKeySink extends Expr {
EncryptionKeySink() {
// `key` arg in `init` is a sink
exists(CallExpr call, string fName |
call.getStaticTarget()
.(MethodDecl)
.hasQualifiedName([
"AES", "HMAC", "ChaCha20", "CBCMAC", "CMAC", "Poly1305", "Blowfish", "Rabbit"
], fName) and
fName.matches("init(key:%") and
call.getArgument(0).getExpr() = this
)
or
// RNCryptor
exists(ClassOrStructDecl c, MethodDecl f, CallExpr call |
c.getFullName() = ["RNCryptor", "RNEncryptor", "RNDecryptor"] and
c.getAMember() = f and
call.getStaticTarget() = f and
call.getArgumentWithLabel(["encryptionKey", "withEncryptionKey"]).getExpr() = this
)
}
}
/**
* A taint configuration from the key source to expressions that use
* it to initialize a cipher.
*/
module HardcodedKeyConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof KeySource }
predicate isSink(DataFlow::Node node) { node.asExpr() instanceof EncryptionKeySink }
}
module HardcodedKeyFlow = TaintTracking::Global<HardcodedKeyConfig>;

View File

@@ -0,0 +1,7 @@
/**
* Provides classes and predicates for reasoning about insecure TLS
* configurations.
*/
import swift
import codeql.swift.dataflow.DataFlow

View File

@@ -0,0 +1,39 @@
/**
* Provides a taint tracking configuration to find insecure TLS
* configurations.
*/
import swift
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.dataflow.FlowSources
import codeql.swift.security.InsecureTLSExtensions
/**
* A taint config to detect insecure configuration of `NSURLSessionConfiguration`
*/
module InsecureTlsConfig implements DataFlow::ConfigSig {
/**
* Holds for enum values that represent an insecure version of TLS
*/
predicate isSource(DataFlow::Node node) {
node.asExpr().(MethodLookupExpr).getMember().(EnumElementDecl).getName() =
["TLSv10", "TLSv11", "tlsProtocol10", "tlsProtocol11"]
}
/**
* Holds for assignment of TLS-related properties of `NSURLSessionConfiguration`
*/
predicate isSink(DataFlow::Node node) {
exists(AssignExpr assign |
assign.getSource() = node.asExpr() and
assign.getDest().(MemberRefExpr).getMember().(ConcreteVarDecl).getName() =
[
"tlsMinimumSupportedProtocolVersion", "tlsMinimumSupportedProtocol",
"tlsMaximumSupportedProtocolVersion", "tlsMaximumSupportedProtocol"
]
)
}
}
module InsecureTlsFlow = TaintTracking::Global<InsecureTlsConfig>;

View File

@@ -0,0 +1,7 @@
/**
* Provides classes and predicates for reasoning about insufficient hash
* iteration vulnerabilities.
*/
import swift
import codeql.swift.dataflow.DataFlow

View File

@@ -0,0 +1,48 @@
/**
* Provides a taint tracking configuration to find insufficient hash
* iteration vulnerabilities.
*/
import swift
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.security.InsufficientHashIterationsQuery
/**
* An `Expr` that is used to initialize a password-based encryption key.
*/
abstract class IterationsSource extends Expr { }
/**
* A literal integer that is 120,000 or less is a source of taint for iterations.
*/
class IntLiteralSource extends IterationsSource instanceof IntegerLiteralExpr {
IntLiteralSource() { this.getStringValue().toInt() < 120000 }
}
/**
* A class for all ways to set the iterations of hash function.
*/
class InsufficientHashIterationsSink extends Expr {
InsufficientHashIterationsSink() {
// `iterations` arg in `init` is a sink
exists(ClassOrStructDecl c, ConstructorDecl f, CallExpr call |
c.getName() = ["PBKDF1", "PBKDF2"] and
c.getAMember() = f and
call.getStaticTarget() = f and
call.getArgumentWithLabel("iterations").getExpr() = this
)
}
}
/**
* A dataflow configuration from the hash iterations source to expressions that use
* it to initialize hash functions.
*/
module InsufficientHashIterationsConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof IterationsSource }
predicate isSink(DataFlow::Node node) { node.asExpr() instanceof InsufficientHashIterationsSink }
}
module InsufficientHashIterationsFlow = TaintTracking::Global<InsufficientHashIterationsConfig>;

View File

@@ -0,0 +1,7 @@
/**
* Provides classes and predicates for reasoning about use of static
* initialization vectors for encryption.
*/
import swift
import codeql.swift.dataflow.DataFlow

View File

@@ -0,0 +1,59 @@
/**
* Provides a taint tracking configuration to find use of static
* initialization vectors for encryption.
*/
import swift
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.security.StaticInitializationVectorExtensions
/**
* A static IV is created through either a byte array or string literals.
*/
class StaticInitializationVectorSource extends Expr {
StaticInitializationVectorSource() {
this instanceof ArrayExpr or
this instanceof StringLiteralExpr or
this instanceof NumberLiteralExpr
}
}
/**
* A class for all ways to set an IV.
*/
class EncryptionInitializationSink extends Expr {
EncryptionInitializationSink() {
// `iv` arg in `init` is a sink
exists(InitializerCallExpr call |
call.getStaticTarget()
.hasQualifiedName([
"AES", "ChaCha20", "Blowfish", "Rabbit", "CBC", "CFB", "GCM", "OCB", "OFB", "PCBC",
"CCM", "CTR"
], _) and
call.getArgumentWithLabel("iv").getExpr() = this
)
or
// RNCryptor
exists(ClassOrStructDecl c, MethodDecl f, CallExpr call |
c.getFullName() = ["RNCryptor", "RNEncryptor", "RNDecryptor"] and
c.getAMember() = f and
call.getStaticTarget() = f and
call.getArgumentWithLabel(["iv", "IV"]).getExpr() = this
)
}
}
/**
* A dataflow configuration from the source of a static IV to expressions that use
* it to initialize a cipher.
*/
module StaticInitializationVectorConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) {
node.asExpr() instanceof StaticInitializationVectorSource
}
predicate isSink(DataFlow::Node node) { node.asExpr() instanceof EncryptionInitializationSink }
}
module StaticInitializationVectorFlow = TaintTracking::Global<StaticInitializationVectorConfig>;

View File

@@ -0,0 +1,8 @@
/**
* Provides classes and predicates for reasoning about use of broken or weak
* cryptographic hashing algorithms on sensitive data.
*/
import swift
import codeql.swift.security.SensitiveExprs
import codeql.swift.dataflow.DataFlow

View File

@@ -0,0 +1,44 @@
/**
* Provides a taint tracking configuration to find use of broken or weak
* cryptographic hashing algorithms on sensitive data.
*/
import swift
import codeql.swift.security.SensitiveExprs
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.security.WeakSensitiveDataHashingExtensions
module WeakHashingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node instanceof WeakHashingConfigImpl::Source }
predicate isSink(DataFlow::Node node) { node instanceof WeakHashingConfigImpl::Sink }
}
module WeakHashingFlow = TaintTracking::Global<WeakHashingConfig>;
module WeakHashingConfigImpl {
class Source extends DataFlow::Node {
Source() { this.asExpr() instanceof SensitiveExpr }
}
abstract class Sink extends DataFlow::Node {
abstract string getAlgorithm();
}
class CryptoHash extends Sink {
string algorithm;
CryptoHash() {
exists(ApplyExpr call, FuncDecl func |
call.getAnArgument().getExpr() = this.asExpr() and
call.getStaticTarget() = func and
func.getName().matches(["hash(%", "update(%"]) and
algorithm = func.getEnclosingDecl().(ClassOrStructDecl).getName() and
algorithm = ["MD5", "SHA1"]
)
}
override string getAlgorithm() { result = algorithm }
}
}

View File

@@ -12,61 +12,9 @@
*/
import swift
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.security.StaticInitializationVectorQuery
import StaticInitializationVectorFlow::PathGraph
/**
* A static IV is created through either a byte array or string literals.
*/
class StaticInitializationVectorSource extends Expr {
StaticInitializationVectorSource() {
this instanceof ArrayExpr or
this instanceof StringLiteralExpr or
this instanceof NumberLiteralExpr
}
}
/**
* A class for all ways to set an IV.
*/
class EncryptionInitializationSink extends Expr {
EncryptionInitializationSink() {
// `iv` arg in `init` is a sink
exists(InitializerCallExpr call |
call.getStaticTarget()
.hasQualifiedName([
"AES", "ChaCha20", "Blowfish", "Rabbit", "CBC", "CFB", "GCM", "OCB", "OFB", "PCBC",
"CCM", "CTR"
], _) and
call.getArgumentWithLabel("iv").getExpr() = this
)
or
// RNCryptor
exists(ClassOrStructDecl c, MethodDecl f, CallExpr call |
c.getFullName() = ["RNCryptor", "RNEncryptor", "RNDecryptor"] and
c.getAMember() = f and
call.getStaticTarget() = f and
call.getArgumentWithLabel(["iv", "IV"]).getExpr() = this
)
}
}
/**
* A dataflow configuration from the source of a static IV to expressions that use
* it to initialize a cipher.
*/
module StaticInitializationVectorConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) {
node.asExpr() instanceof StaticInitializationVectorSource
}
predicate isSink(DataFlow::Node node) { node.asExpr() instanceof EncryptionInitializationSink }
}
module StaticInitializationVectorFlow = TaintTracking::Global<StaticInitializationVectorConfig>;
// The query itself
from
StaticInitializationVectorFlow::PathNode sourceNode,
StaticInitializationVectorFlow::PathNode sinkNode

View File

@@ -11,64 +11,9 @@
*/
import swift
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.dataflow.FlowSteps
import codeql.swift.security.ConstantPasswordQuery
import ConstantPasswordFlow::PathGraph
/**
* A constant password is created through either a byte array or string literals.
*/
class ConstantPasswordSource extends Expr {
ConstantPasswordSource() {
this = any(ArrayExpr arr | arr.getType().getName() = "Array<UInt8>") or
this instanceof StringLiteralExpr
}
}
/**
* A class for all ways to use a constant password.
*/
class ConstantPasswordSink extends Expr {
ConstantPasswordSink() {
// `password` arg in `init` is a sink
exists(ClassOrStructDecl c, ConstructorDecl f, CallExpr call |
c.getName() = ["HKDF", "PBKDF1", "PBKDF2", "Scrypt"] and
c.getAMember() = f and
call.getStaticTarget() = f and
call.getArgumentWithLabel("password").getExpr() = this
)
or
// RNCryptor (labelled arguments)
exists(ClassOrStructDecl c, MethodDecl f, CallExpr call |
c.getName() = ["RNCryptor", "RNEncryptor", "RNDecryptor"] and
c.getAMember() = f and
call.getStaticTarget() = f and
call.getArgumentWithLabel(["password", "withPassword", "forPassword"]).getExpr() = this
)
or
// RNCryptor (unlabelled arguments)
exists(MethodDecl f, CallExpr call |
f.hasQualifiedName("RNCryptor", "keyForPassword(_:salt:settings:)") and
call.getStaticTarget() = f and
call.getArgument(0).getExpr() = this
)
}
}
/**
* A taint configuration from the source of constants passwords to expressions that use
* them to initialize password-based encryption keys.
*/
module ConstantPasswordConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof ConstantPasswordSource }
predicate isSink(DataFlow::Node node) { node.asExpr() instanceof ConstantPasswordSink }
}
module ConstantPasswordFlow = TaintTracking::Global<ConstantPasswordConfig>;
// The query itself
from ConstantPasswordFlow::PathNode sourceNode, ConstantPasswordFlow::PathNode sinkNode
where ConstantPasswordFlow::flowPath(sourceNode, sinkNode)
select sinkNode.getNode(), sourceNode, sinkNode,

View File

@@ -11,66 +11,9 @@
*/
import swift
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.security.HardcodedEncryptionKeyQuery
import HardcodedKeyFlow::PathGraph
/**
* An `Expr` that is used to initialize a key.
*/
abstract class KeySource extends Expr { }
/**
* A literal byte array is a key source.
*/
class ByteArrayLiteralSource extends KeySource {
ByteArrayLiteralSource() { this = any(ArrayExpr arr | arr.getType().getName() = "Array<UInt8>") }
}
/**
* A string literal is a key source.
*/
class StringLiteralSource extends KeySource instanceof StringLiteralExpr { }
/**
* A class for all ways to set a key.
*/
class EncryptionKeySink extends Expr {
EncryptionKeySink() {
// `key` arg in `init` is a sink
exists(CallExpr call, string fName |
call.getStaticTarget()
.(MethodDecl)
.hasQualifiedName([
"AES", "HMAC", "ChaCha20", "CBCMAC", "CMAC", "Poly1305", "Blowfish", "Rabbit"
], fName) and
fName.matches("init(key:%") and
call.getArgument(0).getExpr() = this
)
or
// RNCryptor
exists(ClassOrStructDecl c, MethodDecl f, CallExpr call |
c.getFullName() = ["RNCryptor", "RNEncryptor", "RNDecryptor"] and
c.getAMember() = f and
call.getStaticTarget() = f and
call.getArgumentWithLabel(["encryptionKey", "withEncryptionKey"]).getExpr() = this
)
}
}
/**
* A taint configuration from the key source to expressions that use
* it to initialize a cipher.
*/
module HardcodedKeyConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof KeySource }
predicate isSink(DataFlow::Node node) { node.asExpr() instanceof EncryptionKeySink }
}
module HardcodedKeyFlow = TaintTracking::Global<HardcodedKeyConfig>;
// The query itself
from HardcodedKeyFlow::PathNode sourceNode, HardcodedKeyFlow::PathNode sinkNode
where HardcodedKeyFlow::flowPath(sourceNode, sinkNode)
select sinkNode.getNode(), sourceNode, sinkNode,

View File

@@ -11,63 +11,9 @@
*/
import swift
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.security.ECBEncryptionQuery
import EcbEncryptionFlow::PathGraph
/**
* An `Expr` that is used to initialize the block mode of a cipher.
*/
abstract class BlockMode extends Expr { }
/**
* An `Expr` that is used to form an `AES` cipher.
*/
class AES extends BlockMode {
AES() {
// `blockMode` arg in `AES.init` is a sink
exists(CallExpr call |
call.getStaticTarget()
.(MethodDecl)
.hasQualifiedName("AES", ["init(key:blockMode:)", "init(key:blockMode:padding:)"]) and
call.getArgument(1).getExpr() = this
)
}
}
/**
* An `Expr` that is used to form a `Blowfish` cipher.
*/
class Blowfish extends BlockMode {
Blowfish() {
// `blockMode` arg in `Blowfish.init` is a sink
exists(CallExpr call |
call.getStaticTarget()
.(MethodDecl)
.hasQualifiedName("Blowfish", "init(key:blockMode:padding:)") and
call.getArgument(1).getExpr() = this
)
}
}
/**
* A taint configuration from the constructor of ECB mode to expressions that use
* it to initialize a cipher.
*/
module EcbEncryptionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) {
exists(CallExpr call |
call.getStaticTarget().(MethodDecl).hasQualifiedName("ECB", "init()") and
node.asExpr() = call
)
}
predicate isSink(DataFlow::Node node) { node.asExpr() instanceof BlockMode }
}
module EcbEncryptionFlow = DataFlow::Global<EcbEncryptionConfig>;
// The query itself
from EcbEncryptionFlow::PathNode sourceNode, EcbEncryptionFlow::PathNode sinkNode
where EcbEncryptionFlow::flowPath(sourceNode, sinkNode)
select sinkNode.getNode(), sourceNode, sinkNode,

View File

@@ -12,45 +12,9 @@
*/
import swift
import codeql.swift.security.SensitiveExprs
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.security.WeakSensitiveDataHashingQuery
import WeakHashingFlow::PathGraph
module WeakHashingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node instanceof WeakHashingConfigImpl::Source }
predicate isSink(DataFlow::Node node) { node instanceof WeakHashingConfigImpl::Sink }
}
module WeakHashingFlow = TaintTracking::Global<WeakHashingConfig>;
module WeakHashingConfigImpl {
class Source extends DataFlow::Node {
Source() { this.asExpr() instanceof SensitiveExpr }
}
abstract class Sink extends DataFlow::Node {
abstract string getAlgorithm();
}
class CryptoHash extends Sink {
string algorithm;
CryptoHash() {
exists(ApplyExpr call, FuncDecl func |
call.getAnArgument().getExpr() = this.asExpr() and
call.getStaticTarget() = func and
func.getName().matches(["hash(%", "update(%"]) and
algorithm = func.getEnclosingDecl().(ClassOrStructDecl).getName() and
algorithm = ["MD5", "SHA1"]
)
}
override string getAlgorithm() { result = algorithm }
}
}
from
WeakHashingFlow::PathNode source, WeakHashingFlow::PathNode sink, string algorithm,
SensitiveExpr expr

View File

@@ -11,40 +11,9 @@
*/
import swift
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.dataflow.FlowSources
import codeql.swift.security.InsecureTLSQuery
import InsecureTlsFlow::PathGraph
/**
* A taint config to detect insecure configuration of `NSURLSessionConfiguration`
*/
module InsecureTlsConfig implements DataFlow::ConfigSig {
/**
* Holds for enum values that represent an insecure version of TLS
*/
predicate isSource(DataFlow::Node node) {
node.asExpr().(MethodLookupExpr).getMember().(EnumElementDecl).getName() =
["TLSv10", "TLSv11", "tlsProtocol10", "tlsProtocol11"]
}
/**
* Holds for assignment of TLS-related properties of `NSURLSessionConfiguration`
*/
predicate isSink(DataFlow::Node node) {
exists(AssignExpr assign |
assign.getSource() = node.asExpr() and
assign.getDest().(MemberRefExpr).getMember().(ConcreteVarDecl).getName() =
[
"tlsMinimumSupportedProtocolVersion", "tlsMinimumSupportedProtocol",
"tlsMaximumSupportedProtocolVersion", "tlsMaximumSupportedProtocol"
]
)
}
}
module InsecureTlsFlow = TaintTracking::Global<InsecureTlsConfig>;
from InsecureTlsFlow::PathNode sourceNode, InsecureTlsFlow::PathNode sinkNode
where InsecureTlsFlow::flowPath(sourceNode, sinkNode)
select sinkNode.getNode(), sourceNode, sinkNode, "This TLS configuration is insecure."

View File

@@ -11,58 +11,9 @@
*/
import swift
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.dataflow.FlowSteps
import codeql.swift.security.ConstantSaltQuery
import ConstantSaltFlow::PathGraph
/**
* A constant salt is created through either a byte array or string literals.
*/
class ConstantSaltSource extends Expr {
ConstantSaltSource() {
this = any(ArrayExpr arr | arr.getType().getName() = "Array<UInt8>") or
this instanceof StringLiteralExpr or
this instanceof NumberLiteralExpr
}
}
/**
* A class for all ways to use a constant salt.
*/
class ConstantSaltSink extends Expr {
ConstantSaltSink() {
// `salt` arg in `init` is a sink
exists(ClassOrStructDecl c, ConstructorDecl f, CallExpr call |
c.getName() = ["HKDF", "PBKDF1", "PBKDF2", "Scrypt"] and
c.getAMember() = f and
call.getStaticTarget() = f and
call.getArgumentWithLabel("salt").getExpr() = this
)
or
// RNCryptor
exists(ClassOrStructDecl c, MethodDecl f, CallExpr call |
c.getName() = ["RNCryptor", "RNEncryptor", "RNDecryptor"] and
c.getAMember() = f and
call.getStaticTarget() = f and
call.getArgumentWithLabel(["salt", "encryptionSalt", "hmacSalt", "HMACSalt"]).getExpr() = this
)
}
}
/**
* A taint configuration from the source of constants salts to expressions that use
* them to initialize password-based encryption keys.
*/
module ConstantSaltConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof ConstantSaltSource }
predicate isSink(DataFlow::Node node) { node.asExpr() instanceof ConstantSaltSink }
}
module ConstantSaltFlow = TaintTracking::Global<ConstantSaltConfig>;
// The query itself
from ConstantSaltFlow::PathNode sourceNode, ConstantSaltFlow::PathNode sinkNode
where ConstantSaltFlow::flowPath(sourceNode, sinkNode)
select sinkNode.getNode(), sourceNode, sinkNode,

View File

@@ -11,50 +11,9 @@
*/
import swift
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.security.InsufficientHashIterationsQuery
import InsufficientHashIterationsFlow::PathGraph
/**
* An `Expr` that is used to initialize a password-based encryption key.
*/
abstract class IterationsSource extends Expr { }
/**
* A literal integer that is 120,000 or less is a source of taint for iterations.
*/
class IntLiteralSource extends IterationsSource instanceof IntegerLiteralExpr {
IntLiteralSource() { this.getStringValue().toInt() < 120000 }
}
/**
* A class for all ways to set the iterations of hash function.
*/
class InsufficientHashIterationsSink extends Expr {
InsufficientHashIterationsSink() {
// `iterations` arg in `init` is a sink
exists(ClassOrStructDecl c, ConstructorDecl f, CallExpr call |
c.getName() = ["PBKDF1", "PBKDF2"] and
c.getAMember() = f and
call.getStaticTarget() = f and
call.getArgumentWithLabel("iterations").getExpr() = this
)
}
}
/**
* A dataflow configuration from the hash iterations source to expressions that use
* it to initialize hash functions.
*/
module InsufficientHashIterationsConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof IterationsSource }
predicate isSink(DataFlow::Node node) { node.asExpr() instanceof InsufficientHashIterationsSink }
}
module InsufficientHashIterationsFlow = TaintTracking::Global<InsufficientHashIterationsConfig>;
// The query itself
from
InsufficientHashIterationsFlow::PathNode sourceNode,
InsufficientHashIterationsFlow::PathNode sinkNode