mirror of
https://github.com/github/codeql.git
synced 2026-04-30 03:05:15 +02:00
Merge pull request #12764 from geoffw0/modernsec
Swift: Modernize the encryption queries
This commit is contained in:
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
38
swift/ql/lib/codeql/swift/security/ConstantPasswordQuery.qll
Normal file
38
swift/ql/lib/codeql/swift/security/ConstantPasswordQuery.qll
Normal 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>;
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
39
swift/ql/lib/codeql/swift/security/ConstantSaltQuery.qll
Normal file
39
swift/ql/lib/codeql/swift/security/ConstantSaltQuery.qll
Normal 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>;
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
27
swift/ql/lib/codeql/swift/security/ECBEncryptionQuery.qll
Normal file
27
swift/ql/lib/codeql/swift/security/ECBEncryptionQuery.qll
Normal 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>;
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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>;
|
||||
61
swift/ql/lib/codeql/swift/security/InsecureTLSExtensions.qll
Normal file
61
swift/ql/lib/codeql/swift/security/InsecureTLSExtensions.qll
Normal 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"
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
27
swift/ql/lib/codeql/swift/security/InsecureTLSQuery.qll
Normal file
27
swift/ql/lib/codeql/swift/security/InsecureTLSQuery.qll
Normal 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>;
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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>;
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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>;
|
||||
53
swift/ql/lib/codeql/swift/security/WeakSensitiveDataHashingExtensions.qll
Executable file
53
swift/ql/lib/codeql/swift/security/WeakSensitiveDataHashingExtensions.qll
Executable 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 }
|
||||
}
|
||||
28
swift/ql/lib/codeql/swift/security/WeakSensitiveDataHashingQuery.qll
Executable file
28
swift/ql/lib/codeql/swift/security/WeakSensitiveDataHashingQuery.qll
Executable 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>;
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user