Skip to content

Swift: Add RNCryptor sinks to swift/constant-password #11905

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions swift/ql/src/queries/Security/CWE-259/ConstantPassword.ql
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,21 @@ class ConstantPasswordSink extends Expr {
call.getStaticTarget() = f and
call.getArgumentWithLabel("password").getExpr() = this
)
or
// RNCryptor (labelled arguments)
exists(ClassOrStructDecl c, MethodDecl f, CallExpr call |
c.getFullName() = ["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
)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,72 @@
edges
| rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:77:89:77:89 | myConstPassword |
| rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:78:56:78:56 | myConstPassword |
| rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:80:89:80:89 | myMaybePassword |
| rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:81:56:81:56 | myMaybePassword |
| rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:91:39:91:39 | myConstPassword |
| rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:92:37:92:37 | myConstPassword |
| rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:93:39:93:39 | myConstPassword |
| rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:94:37:94:37 | myConstPassword |
| rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:96:68:96:68 | myConstPassword |
| rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:97:68:97:68 | myConstPassword |
| rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:98:68:98:68 | myConstPassword |
| rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:100:89:100:89 | myConstPassword |
| rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:101:97:101:97 | myConstPassword |
| rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:102:89:102:89 | myConstPassword |
| rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:103:97:103:97 | myConstPassword |
| rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:105:32:105:32 | myConstPassword |
| rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:107:61:107:61 | myConstPassword |
| rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:108:97:108:97 | myConstPassword |
| test.swift:43:39:43:134 | [...] : | test.swift:51:30:51:30 | constantPassword |
| test.swift:43:39:43:134 | [...] : | test.swift:56:40:56:40 | constantPassword |
| test.swift:43:39:43:134 | [...] : | test.swift:62:40:62:40 | constantPassword |
| test.swift:43:39:43:134 | [...] : | test.swift:67:34:67:34 | constantPassword |
nodes
| rncryptor.swift:69:24:69:24 | abc123 : | semmle.label | abc123 : |
| rncryptor.swift:77:89:77:89 | myConstPassword | semmle.label | myConstPassword |
| rncryptor.swift:78:56:78:56 | myConstPassword | semmle.label | myConstPassword |
| rncryptor.swift:80:89:80:89 | myMaybePassword | semmle.label | myMaybePassword |
| rncryptor.swift:81:56:81:56 | myMaybePassword | semmle.label | myMaybePassword |
| rncryptor.swift:91:39:91:39 | myConstPassword | semmle.label | myConstPassword |
| rncryptor.swift:92:37:92:37 | myConstPassword | semmle.label | myConstPassword |
| rncryptor.swift:93:39:93:39 | myConstPassword | semmle.label | myConstPassword |
| rncryptor.swift:94:37:94:37 | myConstPassword | semmle.label | myConstPassword |
| rncryptor.swift:96:68:96:68 | myConstPassword | semmle.label | myConstPassword |
| rncryptor.swift:97:68:97:68 | myConstPassword | semmle.label | myConstPassword |
| rncryptor.swift:98:68:98:68 | myConstPassword | semmle.label | myConstPassword |
| rncryptor.swift:100:89:100:89 | myConstPassword | semmle.label | myConstPassword |
| rncryptor.swift:101:97:101:97 | myConstPassword | semmle.label | myConstPassword |
| rncryptor.swift:102:89:102:89 | myConstPassword | semmle.label | myConstPassword |
| rncryptor.swift:103:97:103:97 | myConstPassword | semmle.label | myConstPassword |
| rncryptor.swift:105:32:105:32 | myConstPassword | semmle.label | myConstPassword |
| rncryptor.swift:107:61:107:61 | myConstPassword | semmle.label | myConstPassword |
| rncryptor.swift:108:97:108:97 | myConstPassword | semmle.label | myConstPassword |
| test.swift:43:39:43:134 | [...] : | semmle.label | [...] : |
| test.swift:51:30:51:30 | constantPassword | semmle.label | constantPassword |
| test.swift:56:40:56:40 | constantPassword | semmle.label | constantPassword |
| test.swift:62:40:62:40 | constantPassword | semmle.label | constantPassword |
| test.swift:67:34:67:34 | constantPassword | semmle.label | constantPassword |
subpaths
#select
| rncryptor.swift:77:89:77:89 | myConstPassword | rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:77:89:77:89 | myConstPassword | The value 'abc123' is used as a constant password. |
| rncryptor.swift:78:56:78:56 | myConstPassword | rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:78:56:78:56 | myConstPassword | The value 'abc123' is used as a constant password. |
| rncryptor.swift:80:89:80:89 | myMaybePassword | rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:80:89:80:89 | myMaybePassword | The value 'abc123' is used as a constant password. |
| rncryptor.swift:81:56:81:56 | myMaybePassword | rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:81:56:81:56 | myMaybePassword | The value 'abc123' is used as a constant password. |
| rncryptor.swift:91:39:91:39 | myConstPassword | rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:91:39:91:39 | myConstPassword | The value 'abc123' is used as a constant password. |
| rncryptor.swift:92:37:92:37 | myConstPassword | rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:92:37:92:37 | myConstPassword | The value 'abc123' is used as a constant password. |
| rncryptor.swift:93:39:93:39 | myConstPassword | rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:93:39:93:39 | myConstPassword | The value 'abc123' is used as a constant password. |
| rncryptor.swift:94:37:94:37 | myConstPassword | rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:94:37:94:37 | myConstPassword | The value 'abc123' is used as a constant password. |
| rncryptor.swift:96:68:96:68 | myConstPassword | rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:96:68:96:68 | myConstPassword | The value 'abc123' is used as a constant password. |
| rncryptor.swift:97:68:97:68 | myConstPassword | rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:97:68:97:68 | myConstPassword | The value 'abc123' is used as a constant password. |
| rncryptor.swift:98:68:98:68 | myConstPassword | rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:98:68:98:68 | myConstPassword | The value 'abc123' is used as a constant password. |
| rncryptor.swift:100:89:100:89 | myConstPassword | rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:100:89:100:89 | myConstPassword | The value 'abc123' is used as a constant password. |
| rncryptor.swift:101:97:101:97 | myConstPassword | rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:101:97:101:97 | myConstPassword | The value 'abc123' is used as a constant password. |
| rncryptor.swift:102:89:102:89 | myConstPassword | rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:102:89:102:89 | myConstPassword | The value 'abc123' is used as a constant password. |
| rncryptor.swift:103:97:103:97 | myConstPassword | rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:103:97:103:97 | myConstPassword | The value 'abc123' is used as a constant password. |
| rncryptor.swift:105:32:105:32 | myConstPassword | rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:105:32:105:32 | myConstPassword | The value 'abc123' is used as a constant password. |
| rncryptor.swift:107:61:107:61 | myConstPassword | rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:107:61:107:61 | myConstPassword | The value 'abc123' is used as a constant password. |
| rncryptor.swift:108:97:108:97 | myConstPassword | rncryptor.swift:69:24:69:24 | abc123 : | rncryptor.swift:108:97:108:97 | myConstPassword | The value 'abc123' is used as a constant password. |
| test.swift:51:30:51:30 | constantPassword | test.swift:43:39:43:134 | [...] : | test.swift:51:30:51:30 | constantPassword | The value '[...]' is used as a constant password. |
| test.swift:56:40:56:40 | constantPassword | test.swift:43:39:43:134 | [...] : | test.swift:56:40:56:40 | constantPassword | The value '[...]' is used as a constant password. |
| test.swift:62:40:62:40 | constantPassword | test.swift:43:39:43:134 | [...] : | test.swift:62:40:62:40 | constantPassword | The value '[...]' is used as a constant password. |
| test.swift:67:34:67:34 | constantPassword | test.swift:43:39:43:134 | [...] : | test.swift:67:34:67:34 | constantPassword | The value '[...]' is used as a constant password. |
| test.swift:67:34:67:34 | constantPassword | test.swift:43:39:43:134 | [...] : | test.swift:67:34:67:34 | constantPassword | The value '[...]' is used as a constant password. |
109 changes: 109 additions & 0 deletions swift/ql/test/query-tests/Security/CWE-259/rncryptor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@

// --- stubs ---

class Data {
init<S>(_ elements: S) {}
}

class NSObject
{
}

struct _RNCryptorSettings {
// ...
}
typealias RNCryptorSettings = _RNCryptorSettings

let kRNCryptorAES256Settings = RNCryptorSettings()

struct _RNCryptorKeyDerivationSettings {
// ...
}
typealias RNCryptorKeyDerivationSettings = _RNCryptorKeyDerivationSettings

typealias RNCryptorHandler = () -> Void // simplified

class RNCryptor : NSObject
{
func key(forPassword password: String?, salt: Data?, settings keySettings: RNCryptorKeyDerivationSettings) -> Data? { return nil }
func keyForPassword(_ password: String?, salt: Data?, settings keySettings: RNCryptorKeyDerivationSettings) -> Data? { return nil }
}

class RNEncryptor : RNCryptor
{
override init() {}

init(settings: RNCryptorSettings, password: String?, handler: RNCryptorHandler?) {}
init(settings: RNCryptorSettings, password: String, iv anIV: Data?, encryptionSalt anEncryptionSalt: Data?, hmacSalt anHMACSalt: Data?, handler: RNCryptorHandler?) {}
init(settings: RNCryptorSettings, password: String, IV anIV: Data?, encryptionSalt anEncryptionSalt: Data?, HMACSalt anHMACSalt: Data?, handler: RNCryptorHandler?) {}

func encryptData(_ data: Data?, with settings: RNCryptorSettings, password: String?) throws -> Data { return Data(0) }
func encryptData(_ data: Data?, withSettings settings: RNCryptorSettings, password: String?) throws -> Data { return Data(0) }
func encryptData(_ data: Data?, with settings: RNCryptorSettings, password: String?, iv anIV: Data?, encryptionSalt anEncryptionSalt: Data?, hmacSalt anHMACSalt: Data?) throws -> Data { return Data(0) }
func encryptData(_ data: Data?, withSettings settings: RNCryptorSettings, password: String?, IV anIV: Data?, encryptionSalt anEncryptionSalt: Data?, HMACSalt anHMACSalt: Data?) throws -> Data { return Data(0) }
}

class RNDecryptor : RNCryptor
{
override init() {}

init(password: String?, handler: RNCryptorHandler?) {}

func decryptData(_ data: Data?, withPassword password: String?) throws -> Data { return Data(0) }
func decryptData(_ theCipherText: Data?, withSettings settings: RNCryptorSettings, password aPassword: String?) throws -> Data { return Data(0) }
}

// --- tests ---

func getARandomPassword() -> String {
let charset = "abcdefghijklmnopqrstuvwxyz1234567890"
return String("............".map{_ in charset.randomElement()!})
}

func test(cond: Bool) {
let myEncryptor = RNEncryptor()
let myDecryptor = RNDecryptor()
let myData = Data(0)

let myRandomPassword = getARandomPassword()
let myConstPassword = "abc123"
let myMaybePassword = cond ? myRandomPassword : myConstPassword

// reasonable usage

let a = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myRandomPassword) // GOOD
let _ = try? myDecryptor.decryptData(a, withPassword: myRandomPassword) // GOOD

let b = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myConstPassword) // BAD
let _ = try? myDecryptor.decryptData(b, withPassword: myConstPassword) // BAD

let c = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myMaybePassword) // BAD
let _ = try? myDecryptor.decryptData(c, withPassword: myMaybePassword) // BAD

// all methods

let myKeyDerivationSettings = RNCryptorKeyDerivationSettings()
let myHandler = {}
let myIV = Data(0)
let mySalt = Data(0)
let mySalt2 = Data(0)

let _ = myEncryptor.key(forPassword: myConstPassword, salt: mySalt, settings: myKeyDerivationSettings) // BAD
let _ = myEncryptor.keyForPassword(myConstPassword, salt: mySalt, settings: myKeyDerivationSettings) // BAD
let _ = myDecryptor.key(forPassword: myConstPassword, salt: mySalt, settings: myKeyDerivationSettings) // BAD
let _ = myDecryptor.keyForPassword(myConstPassword, salt: mySalt, settings: myKeyDerivationSettings) // BAD

let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myConstPassword, handler: myHandler) // BAD
let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myConstPassword, iv: myIV, encryptionSalt: mySalt, hmacSalt: mySalt2, handler: myHandler) // BAD
let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myConstPassword, IV: myIV, encryptionSalt: mySalt, HMACSalt: mySalt2, handler: myHandler) // BAD

let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myConstPassword) // BAD
let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, password: myConstPassword) // BAD
let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myConstPassword, iv: myIV, encryptionSalt: mySalt, hmacSalt: mySalt2) // BAD
let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, password: myConstPassword, IV: myIV, encryptionSalt: mySalt, HMACSalt: mySalt2) // BAD

let _ = RNDecryptor(password: myConstPassword, handler: myHandler) // BAD

let _ = try? myDecryptor.decryptData(myData, withPassword: myConstPassword) // BAD
let _ = try? myDecryptor.decryptData(myData, withSettings: kRNCryptorAES256Settings, password: myConstPassword) // BAD
}