Merge pull request #12764 from geoffw0/modernsec

Swift: Modernize the encryption queries
This commit is contained in:
Geoffrey White
2023-04-06 13:26:32 +01:00
committed by GitHub
24 changed files with 776 additions and 384 deletions

View File

@@ -0,0 +1,67 @@
/**
* Provides classes and predicates for reasoning about constant password
* vulnerabilities.
*/
import swift
import codeql.swift.dataflow.DataFlow
/**
* A dataflow sink for constant password vulnerabilities. That is,
* a `DataFlow::Node` of something that is used as a password.
*/
abstract class ConstantPasswordSink extends DataFlow::Node { }
/**
* A sanitizer for constant password vulnerabilities.
*/
abstract class ConstantPasswordSanitizer extends DataFlow::Node { }
/**
* A unit class for adding additional taint steps.
*/
class ConstantPasswordAdditionalTaintStep extends Unit {
/**
* Holds if the step from `node1` to `node2` should be considered a taint
* step for paths related to constant password vulnerabilities.
*/
abstract predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo);
}
/**
* A password sink for the CryptoSwift library.
*/
private class DefaultConstantPasswordSink extends ConstantPasswordSink {
DefaultConstantPasswordSink() {
// `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.asExpr()
)
}
}
/**
* A password sink for the RNCryptor library.
*/
private class RnCryptorPasswordSink extends ConstantPasswordSink {
RnCryptorPasswordSink() {
// 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.asExpr()
)
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.asExpr()
)
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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 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 instanceof ConstantPasswordSink }
predicate isBarrier(DataFlow::Node node) { node instanceof ConstantPasswordSanitizer }
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
any(ConstantPasswordAdditionalTaintStep s).step(nodeFrom, nodeTo)
}
}
module ConstantPasswordFlow = TaintTracking::Global<ConstantPasswordConfig>;

View File

@@ -0,0 +1,59 @@
/**
* Provides classes and predicates for reasoning about use of constant salts
* for password hashing.
*/
import swift
import codeql.swift.dataflow.DataFlow
/**
* A dataflow sink for constant salt vulnerabilities. That is,
* a `DataFlow::Node` of something that is used as a salt.
*/
abstract class ConstantSaltSink extends DataFlow::Node { }
/**
* A sanitizer for constant salt vulnerabilities.
*/
abstract class ConstantSaltSanitizer extends DataFlow::Node { }
/**
* A unit class for adding additional taint steps.
*/
class ConstantSaltAdditionalTaintStep extends Unit {
/**
* Holds if the step from `node1` to `node2` should be considered a taint
* step for paths related to constant salt vulnerabilities.
*/
abstract predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo);
}
/**
* A sink for the CryptoSwift library.
*/
private class CryptoSwiftSaltSink extends ConstantSaltSink {
CryptoSwiftSaltSink() {
// `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.asExpr()
)
}
}
/**
* A sink for the RNCryptor library.
*/
private class RnCryptorSaltSink extends ConstantSaltSink {
RnCryptorSaltSink() {
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.asExpr()
)
}
}

View File

@@ -0,0 +1,39 @@
/**
* 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 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 instanceof ConstantSaltSink }
predicate isBarrier(DataFlow::Node node) { node instanceof ConstantSaltSanitizer }
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
any(ConstantSaltAdditionalTaintStep s).step(nodeFrom, nodeTo)
}
}
module ConstantSaltFlow = TaintTracking::Global<ConstantSaltConfig>;

View File

@@ -0,0 +1,79 @@
/**
* Provides classes and predicates for reasoning about encryption using the
* ECB encryption mode.
*/
import swift
import codeql.swift.dataflow.DataFlow
/**
* A dataflow source for ECB encryption vulnerabilities. That is,
* a `DataFlow::Node` of something that specifies a block mode
* cipher.
*/
abstract class EcbEncryptionSource extends DataFlow::Node { }
/**
* A dataflow sink for ECB encryption vulnerabilities. That is,
* a `DataFlow::Node` of something that is used as the block mode
* of a cipher.
*/
abstract class EcbEncryptionSink extends DataFlow::Node { }
/**
* A sanitizer for ECB encryption vulnerabilities.
*/
abstract class EcbEncryptionSanitizer extends DataFlow::Node { }
/**
* A unit class for adding additional taint steps.
*/
class EcbEncryptionAdditionalTaintStep extends Unit {
/**
* Holds if the step from `node1` to `node2` should be considered a taint
* step for paths related to ECB encryption vulnerabilities.
*/
abstract predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo);
}
/**
* A block mode for the CryptoSwift library.
*/
private class CryptoSwiftEcb extends EcbEncryptionSource {
CryptoSwiftEcb() {
exists(CallExpr call |
call.getStaticTarget().(MethodDecl).hasQualifiedName("ECB", "init()") and
this.asExpr() = call
)
}
}
/**
* A block mode being used to form a CryptoSwift `AES` cipher.
*/
private class AES extends EcbEncryptionSink {
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.asExpr()
)
}
}
/**
* A block mode being used to form a CryptoSwift `Blowfish` cipher.
*/
private class Blowfish extends EcbEncryptionSink {
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.asExpr()
)
}
}

View File

@@ -0,0 +1,27 @@
/**
* Provides a taint tracking configuration to find encryption using the
* ECB encryption mode.
*/
import swift
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.security.ECBEncryptionExtensions
/**
* 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) { node instanceof EcbEncryptionSource }
predicate isSink(DataFlow::Node node) { node instanceof EcbEncryptionSink }
predicate isBarrier(DataFlow::Node node) { node instanceof EcbEncryptionSanitizer }
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
any(EcbEncryptionAdditionalTaintStep s).step(nodeFrom, nodeTo)
}
}
module EcbEncryptionFlow = DataFlow::Global<EcbEncryptionConfig>;

View File

@@ -0,0 +1,61 @@
/**
* Provides classes and predicates for reasoning about hard-coded encryption
* key vulnerabilities.
*/
import swift
import codeql.swift.dataflow.DataFlow
/**
* A dataflow sink for hard-coded encryption key vulnerabilities. That is,
* a `DataFlow::Node` of something that is used as a key.
*/
abstract class HardcodedEncryptionKeySink extends DataFlow::Node { }
/**
* A sanitizer for hard-coded encryption key vulnerabilities.
*/
abstract class HardcodedEncryptionKeySanitizer extends DataFlow::Node { }
/**
* A unit class for adding additional taint steps.
*/
class HardcodedEncryptionKeyAdditionalTaintStep extends Unit {
/**
* Holds if the step from `node1` to `node2` should be considered a taint
* step for paths related to hard-coded encryption key vulnerabilities.
*/
abstract predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo);
}
/**
* A sink for the CryptoSwift library.
*/
private class CryptoSwiftEncryptionKeySink extends HardcodedEncryptionKeySink {
CryptoSwiftEncryptionKeySink() {
// `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.asExpr()
)
}
}
/**
* A sink for the RNCryptor library.
*/
private class RnCryptorEncryptionKeySink extends HardcodedEncryptionKeySink {
RnCryptorEncryptionKeySink() {
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.asExpr()
)
}
}

View File

@@ -0,0 +1,44 @@
/**
* 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 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 instanceof HardcodedEncryptionKeySink }
predicate isBarrier(DataFlow::Node node) { node instanceof HardcodedEncryptionKeySanitizer }
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
any(HardcodedEncryptionKeyAdditionalTaintStep s).step(nodeFrom, nodeTo)
}
}
module HardcodedKeyFlow = TaintTracking::Global<HardcodedKeyConfig>;

View File

@@ -0,0 +1,61 @@
/**
* Provides classes and predicates for reasoning about insecure TLS
* configurations.
*/
import swift
import codeql.swift.dataflow.DataFlow
/**
* A dataflow source for insecure TLS configuration vulnerabilities. That is,
* a `DataFlow::Node` for something that is an insecure TLS version.
*/
abstract class InsecureTlsExtensionsSource extends DataFlow::Node { }
/**
* A dataflow sink for insecure TLS configuration vulnerabilities. That is,
* a `DataFlow::Node` of something that is used as a TLS version.
*/
abstract class InsecureTlsExtensionsSink extends DataFlow::Node { }
/**
* A sanitizer for insecure TLS configuration vulnerabilities.
*/
abstract class InsecureTlsExtensionsSanitizer extends DataFlow::Node { }
/**
* A unit class for adding additional taint steps.
*/
class InsecureTlsExtensionsAdditionalTaintStep extends Unit {
/**
* Holds if the step from `node1` to `node2` should be considered a taint
* step for paths related to insecure TLS configuration vulnerabilities.
*/
abstract predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo);
}
/**
* A source for enum values that represent an insecure version of TLS.
*/
private class EnumInsecureTlsExtensionsSource extends InsecureTlsExtensionsSource {
EnumInsecureTlsExtensionsSource() {
this.asExpr().(MethodLookupExpr).getMember().(EnumElementDecl).getName() =
["TLSv10", "TLSv11", "tlsProtocol10", "tlsProtocol11"]
}
}
/**
* A sink for assignment of TLS-related properties of `NSURLSessionConfiguration`.
*/
private class NsUrlTlsExtensionsSink extends InsecureTlsExtensionsSink {
NsUrlTlsExtensionsSink() {
exists(AssignExpr assign |
assign.getSource() = this.asExpr() and
assign.getDest().(MemberRefExpr).getMember().(ConcreteVarDecl).getName() =
[
"tlsMinimumSupportedProtocolVersion", "tlsMinimumSupportedProtocol",
"tlsMaximumSupportedProtocolVersion", "tlsMaximumSupportedProtocol"
]
)
}
}

View File

@@ -0,0 +1,27 @@
/**
* 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 {
predicate isSource(DataFlow::Node node) { node instanceof InsecureTlsExtensionsSource }
predicate isSink(DataFlow::Node node) { node instanceof InsecureTlsExtensionsSink }
predicate isBarrier(DataFlow::Node node) { node instanceof InsecureTlsExtensionsSanitizer }
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
any(InsecureTlsExtensionsAdditionalTaintStep s).step(nodeFrom, nodeTo)
}
}
module InsecureTlsFlow = TaintTracking::Global<InsecureTlsConfig>;

View File

@@ -0,0 +1,45 @@
/**
* Provides classes and predicates for reasoning about insufficient hash
* iteration vulnerabilities.
*/
import swift
import codeql.swift.dataflow.DataFlow
/**
* A dataflow sink for insufficient hash interation vulnerabilities. That is,
* a `DataFlow::Node` of something that is used as the iteration count of a
* hash function.
*/
abstract class InsufficientHashIterationsSink extends DataFlow::Node { }
/**
* A sanitizer for insufficient hash interation vulnerabilities.
*/
abstract class InsufficientHashIterationsSanitizer extends DataFlow::Node { }
/**
* A unit class for adding additional taint steps.
*/
class InsufficientHashIterationsAdditionalTaintStep extends Unit {
/**
* Holds if the step from `node1` to `node2` should be considered a taint
* step for paths related to insufficient hash interation vulnerabilities.
*/
abstract predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo);
}
/**
* A sink for the CryptoSwift library.
*/
private class CryptoSwiftHashIterationsSink extends InsufficientHashIterationsSink {
CryptoSwiftHashIterationsSink() {
// `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.asExpr()
)
}
}

View File

@@ -0,0 +1,39 @@
/**
* 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.InsufficientHashIterationsExtensions
/**
* An `Expr` that is used to initialize a password-based encryption key.
*/
abstract private class IterationsSource extends Expr { }
/**
* A literal integer that is 120,000 or less is a source of taint for iterations.
*/
private class IntLiteralSource extends IterationsSource instanceof IntegerLiteralExpr {
IntLiteralSource() { this.getStringValue().toInt() < 120000 }
}
/**
* A taint tracking 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 instanceof InsufficientHashIterationsSink }
predicate isBarrier(DataFlow::Node node) { node instanceof InsufficientHashIterationsSanitizer }
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
any(InsufficientHashIterationsAdditionalTaintStep s).step(nodeFrom, nodeTo)
}
}
module InsufficientHashIterationsFlow = TaintTracking::Global<InsufficientHashIterationsConfig>;

View File

@@ -0,0 +1,60 @@
/**
* Provides classes and predicates for reasoning about use of static
* initialization vectors for encryption.
*/
import swift
import codeql.swift.dataflow.DataFlow
/**
* A dataflow sink for static initialization vector vulnerabilities. That is,
* a `DataFlow::Node` that is something used as an initialization vector.
*/
abstract class StaticInitializationVectorSink extends DataFlow::Node { }
/**
* A sanitizer for static initialization vector vulnerabilities.
*/
abstract class StaticInitializationVectorSanitizer extends DataFlow::Node { }
/**
* A unit class for adding additional taint steps.
*/
class StaticInitializationVectorAdditionalTaintStep extends Unit {
/**
* Holds if the step from `node1` to `node2` should be considered a taint
* step for paths related to static initialization vector vulnerabilities.
*/
abstract predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo);
}
/**
* An initialization vector sink for various CryptoSwift encryption classes.
*/
private class CryptoSwiftInitializationVectorSink extends StaticInitializationVectorSink {
CryptoSwiftInitializationVectorSink() {
// `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.asExpr()
)
}
}
/**
* An initialization vector sink for the `RNCryptor` library.
*/
private class RnCryptorInitializationVectorSink extends StaticInitializationVectorSink {
RnCryptorInitializationVectorSink() {
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.asExpr()
)
}
}

View File

@@ -0,0 +1,40 @@
/**
* 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 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 instanceof StaticInitializationVectorSink }
predicate isBarrier(DataFlow::Node node) { node instanceof StaticInitializationVectorSanitizer }
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
any(StaticInitializationVectorAdditionalTaintStep s).step(nodeFrom, nodeTo)
}
}
module StaticInitializationVectorFlow = TaintTracking::Global<StaticInitializationVectorConfig>;

View File

@@ -0,0 +1,53 @@
/**
* 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
/**
* A dataflow sink for weak sensitive data hashing vulnerabilities.
*/
abstract class WeakSensitiveDataHashingSink extends DataFlow::Node {
/**
* Gets the name of the hashing algorithm, for display.
*/
abstract string getAlgorithm();
}
/**
* A sanitizer for weak sensitive data hashing vulnerabilities.
*/
abstract class WeakSensitiveDataHashingSanitizer extends DataFlow::Node { }
/**
* A unit class for adding additional taint steps.
*/
class WeakSensitiveDataHashingAdditionalTaintStep extends Unit {
/**
* Holds if the step from `node1` to `node2` should be considered a taint
* step for paths related to weak sensitive data hashing vulnerabilities.
*/
abstract predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo);
}
/**
* A sink for the CryptoSwift library.
*/
private class CryptoSwiftWeakHashingSink extends WeakSensitiveDataHashingSink {
string algorithm;
CryptoSwiftWeakHashingSink() {
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

@@ -0,0 +1,28 @@
/**
* 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
/**
* A taint tracking configuration from sensitive expressions to broken or weak
* hashing sinks.
*/
module WeakHashingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof SensitiveExpr }
predicate isSink(DataFlow::Node node) { node instanceof WeakSensitiveDataHashingSink }
predicate isBarrier(DataFlow::Node node) { node instanceof WeakSensitiveDataHashingSanitizer }
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
any(WeakSensitiveDataHashingAdditionalTaintStep s).step(nodeFrom, nodeTo)
}
}
module WeakHashingFlow = TaintTracking::Global<WeakHashingConfig>;

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,51 +12,15 @@
*/
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
where
WeakHashingFlow::flowPath(source, sink) and
algorithm = sink.getNode().(WeakHashingConfigImpl::Sink).getAlgorithm() and
algorithm = sink.getNode().(WeakSensitiveDataHashingSink).getAlgorithm() and
expr = source.getNode().asExpr()
select sink.getNode(), source, sink,
"Insecure hashing algorithm (" + algorithm + ") depends on $@.", source.getNode(),

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