diff --git a/swift/ql/src/queries/Security/CWE-1204/StaticInitializationVector.ql b/swift/ql/src/queries/Security/CWE-1204/StaticInitializationVector.ql index 9ac4ce8922fb..0324be01da99 100644 --- a/swift/ql/src/queries/Security/CWE-1204/StaticInitializationVector.ql +++ b/swift/ql/src/queries/Security/CWE-1204/StaticInitializationVector.ql @@ -21,8 +21,9 @@ import DataFlow::PathGraph */ class StaticInitializationVectorSource extends Expr { StaticInitializationVectorSource() { - this = any(ArrayExpr arr | arr.getType().getName() = "Array") or - this instanceof StringLiteralExpr + this instanceof ArrayExpr or + this instanceof StringLiteralExpr or + this instanceof NumberLiteralExpr } } @@ -40,6 +41,14 @@ class EncryptionInitializationSink extends Expr { ], _) 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 + ) } } diff --git a/swift/ql/test/query-tests/Security/CWE-1204/StaticInitializationVector.expected b/swift/ql/test/query-tests/Security/CWE-1204/StaticInitializationVector.expected index 467ca5c86a97..d98cdc3ef783 100644 --- a/swift/ql/test/query-tests/Security/CWE-1204/StaticInitializationVector.expected +++ b/swift/ql/test/query-tests/Security/CWE-1204/StaticInitializationVector.expected @@ -1,4 +1,21 @@ edges +| rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in Data.init(_:) : | +| rncryptor.swift:60:19:60:25 | call to Data.init(_:) : | rncryptor.swift:68:104:68:104 | myConstIV1 | +| rncryptor.swift:60:19:60:25 | call to Data.init(_:) : | rncryptor.swift:77:125:77:125 | myConstIV1 | +| rncryptor.swift:60:24:60:24 | 0 : | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) : | +| rncryptor.swift:60:24:60:24 | 0 : | rncryptor.swift:60:19:60:25 | call to Data.init(_:) : | +| rncryptor.swift:61:19:61:27 | call to Data.init(_:) : | rncryptor.swift:70:104:70:104 | myConstIV2 | +| rncryptor.swift:61:19:61:27 | call to Data.init(_:) : | rncryptor.swift:79:133:79:133 | myConstIV2 | +| rncryptor.swift:61:24:61:24 | 123 : | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) : | +| rncryptor.swift:61:24:61:24 | 123 : | rncryptor.swift:61:19:61:27 | call to Data.init(_:) : | +| rncryptor.swift:62:19:62:35 | call to Data.init(_:) : | rncryptor.swift:72:84:72:84 | myConstIV3 | +| rncryptor.swift:62:19:62:35 | call to Data.init(_:) : | rncryptor.swift:81:105:81:105 | myConstIV3 | +| rncryptor.swift:62:24:62:34 | [...] : | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) : | +| rncryptor.swift:62:24:62:34 | [...] : | rncryptor.swift:62:19:62:35 | call to Data.init(_:) : | +| rncryptor.swift:63:19:63:28 | call to Data.init(_:) : | rncryptor.swift:74:84:74:84 | myConstIV4 | +| rncryptor.swift:63:19:63:28 | call to Data.init(_:) : | rncryptor.swift:83:113:83:113 | myConstIV4 | +| rncryptor.swift:63:24:63:24 | iv : | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) : | +| rncryptor.swift:63:24:63:24 | iv : | rncryptor.swift:63:19:63:28 | call to Data.init(_:) : | | test.swift:53:19:53:34 | iv : | test.swift:54:17:54:17 | iv | | test.swift:85:3:85:3 | this string is constant : | test.swift:101:17:101:35 | call to getConstantString() : | | test.swift:99:25:99:120 | [...] : | test.swift:128:33:128:33 | iv | @@ -23,6 +40,24 @@ edges | test.swift:101:17:101:35 | call to getConstantString() : | test.swift:130:39:130:39 | ivString | | test.swift:147:22:147:22 | iv : | test.swift:53:19:53:34 | iv : | nodes +| file://:0:0:0:0 | [summary] to write: return (return) in Data.init(_:) : | semmle.label | [summary] to write: return (return) in Data.init(_:) : | +| rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) : | semmle.label | [summary param] 0 in Data.init(_:) : | +| rncryptor.swift:60:19:60:25 | call to Data.init(_:) : | semmle.label | call to Data.init(_:) : | +| rncryptor.swift:60:24:60:24 | 0 : | semmle.label | 0 : | +| rncryptor.swift:61:19:61:27 | call to Data.init(_:) : | semmle.label | call to Data.init(_:) : | +| rncryptor.swift:61:24:61:24 | 123 : | semmle.label | 123 : | +| rncryptor.swift:62:19:62:35 | call to Data.init(_:) : | semmle.label | call to Data.init(_:) : | +| rncryptor.swift:62:24:62:34 | [...] : | semmle.label | [...] : | +| rncryptor.swift:63:19:63:28 | call to Data.init(_:) : | semmle.label | call to Data.init(_:) : | +| rncryptor.swift:63:24:63:24 | iv : | semmle.label | iv : | +| rncryptor.swift:68:104:68:104 | myConstIV1 | semmle.label | myConstIV1 | +| rncryptor.swift:70:104:70:104 | myConstIV2 | semmle.label | myConstIV2 | +| rncryptor.swift:72:84:72:84 | myConstIV3 | semmle.label | myConstIV3 | +| rncryptor.swift:74:84:74:84 | myConstIV4 | semmle.label | myConstIV4 | +| rncryptor.swift:77:125:77:125 | myConstIV1 | semmle.label | myConstIV1 | +| rncryptor.swift:79:133:79:133 | myConstIV2 | semmle.label | myConstIV2 | +| rncryptor.swift:81:105:81:105 | myConstIV3 | semmle.label | myConstIV3 | +| rncryptor.swift:83:113:83:113 | myConstIV4 | semmle.label | myConstIV4 | | test.swift:53:19:53:34 | iv : | semmle.label | iv : | | test.swift:54:17:54:17 | iv | semmle.label | iv | | test.swift:85:3:85:3 | this string is constant : | semmle.label | this string is constant : | @@ -49,7 +84,19 @@ nodes | test.swift:167:22:167:22 | iv | semmle.label | iv | | test.swift:168:22:168:22 | iv | semmle.label | iv | subpaths +| rncryptor.swift:60:24:60:24 | 0 : | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in Data.init(_:) : | rncryptor.swift:60:19:60:25 | call to Data.init(_:) : | +| rncryptor.swift:61:24:61:24 | 123 : | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in Data.init(_:) : | rncryptor.swift:61:19:61:27 | call to Data.init(_:) : | +| rncryptor.swift:62:24:62:34 | [...] : | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in Data.init(_:) : | rncryptor.swift:62:19:62:35 | call to Data.init(_:) : | +| rncryptor.swift:63:24:63:24 | iv : | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in Data.init(_:) : | rncryptor.swift:63:19:63:28 | call to Data.init(_:) : | #select +| rncryptor.swift:68:104:68:104 | myConstIV1 | rncryptor.swift:60:24:60:24 | 0 : | rncryptor.swift:68:104:68:104 | myConstIV1 | The static value '0' is used as an initialization vector for encryption. | +| rncryptor.swift:70:104:70:104 | myConstIV2 | rncryptor.swift:61:24:61:24 | 123 : | rncryptor.swift:70:104:70:104 | myConstIV2 | The static value '123' is used as an initialization vector for encryption. | +| rncryptor.swift:72:84:72:84 | myConstIV3 | rncryptor.swift:62:24:62:34 | [...] : | rncryptor.swift:72:84:72:84 | myConstIV3 | The static value '[...]' is used as an initialization vector for encryption. | +| rncryptor.swift:74:84:74:84 | myConstIV4 | rncryptor.swift:63:24:63:24 | iv : | rncryptor.swift:74:84:74:84 | myConstIV4 | The static value 'iv' is used as an initialization vector for encryption. | +| rncryptor.swift:77:125:77:125 | myConstIV1 | rncryptor.swift:60:24:60:24 | 0 : | rncryptor.swift:77:125:77:125 | myConstIV1 | The static value '0' is used as an initialization vector for encryption. | +| rncryptor.swift:79:133:79:133 | myConstIV2 | rncryptor.swift:61:24:61:24 | 123 : | rncryptor.swift:79:133:79:133 | myConstIV2 | The static value '123' is used as an initialization vector for encryption. | +| rncryptor.swift:81:105:81:105 | myConstIV3 | rncryptor.swift:62:24:62:34 | [...] : | rncryptor.swift:81:105:81:105 | myConstIV3 | The static value '[...]' is used as an initialization vector for encryption. | +| rncryptor.swift:83:113:83:113 | myConstIV4 | rncryptor.swift:63:24:63:24 | iv : | rncryptor.swift:83:113:83:113 | myConstIV4 | The static value 'iv' is used as an initialization vector for encryption. | | test.swift:54:17:54:17 | iv | test.swift:99:25:99:120 | [...] : | test.swift:54:17:54:17 | iv | The static value '[...]' is used as an initialization vector for encryption. | | test.swift:112:36:112:36 | ivString | test.swift:85:3:85:3 | this string is constant : | test.swift:112:36:112:36 | ivString | The static value 'this string is constant' is used as an initialization vector for encryption. | | test.swift:113:36:113:36 | ivString | test.swift:85:3:85:3 | this string is constant : | test.swift:113:36:113:36 | ivString | The static value 'this string is constant' is used as an initialization vector for encryption. | diff --git a/swift/ql/test/query-tests/Security/CWE-1204/rncryptor.swift b/swift/ql/test/query-tests/Security/CWE-1204/rncryptor.swift new file mode 100644 index 000000000000..253804cabf15 --- /dev/null +++ b/swift/ql/test/query-tests/Security/CWE-1204/rncryptor.swift @@ -0,0 +1,84 @@ + +// --- stubs --- + +class Data { + init(_ elements: S) {} +} + +class NSObject +{ +} + +struct _RNCryptorSettings { + // ... +} +typealias RNCryptorSettings = _RNCryptorSettings + +let kRNCryptorAES256Settings = RNCryptorSettings() + +struct _RNCryptorKeyDerivationSettings { + // ... +} +typealias RNCryptorKeyDerivationSettings = _RNCryptorKeyDerivationSettings + +typealias RNCryptorHandler = () -> Void // simplified + +class RNCryptor : NSObject +{ +} + +class RNEncryptor : RNCryptor +{ + override init() {} + + init(settings theSettings: RNCryptorSettings, encryptionKey anEncryptionKey: Data?, hmacKey anHMACKey: Data?, iv anIV: Data?, handler aHandler: RNCryptorHandler?) {} + init(settings theSettings: RNCryptorSettings, encryptionKey anEncryptionKey: Data?, HMACKey anHMACKey: Data?, IV anIV: Data?, handler aHandler: 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(_ thePlaintext: Data?, with theSettings: RNCryptorSettings, encryptionKey anEncryptionKey: Data?, hmacKey anHMACKey: Data?, iv anIV: Data?) throws -> Data { return Data(0) } + func encryptData(_ thePlaintext: Data?, withSettings theSettings: RNCryptorSettings, encryptionKey anEncryptionKey: Data?, HMACKey anHMACKey: Data?, IV anIV: Data?) 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) } +} + +// --- tests --- + +func getRandomArray() -> [UInt8] { + (0..<12).map({ _ in UInt8.random(in: 0...UInt8.max) }) +} + +func test(myPassword: String) { + // RNCryptor + let myEncryptor = RNEncryptor() + let myData = Data(0) + let myKey = Data(0) + let myHMACKey = Data(0) + let myKeyDerivationSettings = RNCryptorKeyDerivationSettings() + let myHandler = {} + let myRandomIV = Data(getRandomArray()) + let myConstIV1 = Data(0) + let myConstIV2 = Data(123) + let myConstIV3 = Data([1,2,3,4,5]) + let myConstIV4 = Data("iv") + let mySalt = Data(0) + let mySalt2 = Data(0) + + let _ = RNEncryptor(settings: kRNCryptorAES256Settings, encryptionKey: myKey, hmacKey: myHMACKey, iv: myRandomIV, handler: myHandler) // GOOD + let _ = RNEncryptor(settings: kRNCryptorAES256Settings, encryptionKey: myKey, hmacKey: myHMACKey, iv: myConstIV1, handler: myHandler) // BAD + let _ = RNEncryptor(settings: kRNCryptorAES256Settings, encryptionKey: myKey, HMACKey: myHMACKey, IV: myRandomIV, handler: myHandler) // GOOD + let _ = RNEncryptor(settings: kRNCryptorAES256Settings, encryptionKey: myKey, HMACKey: myHMACKey, IV: myConstIV2, handler: myHandler) // BAD + let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, iv: myRandomIV, encryptionSalt: mySalt, hmacSalt: mySalt2, handler: myHandler) // GOOD + let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, iv: myConstIV3, encryptionSalt: mySalt, hmacSalt: mySalt2, handler: myHandler) // BAD + let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, IV: myRandomIV, encryptionSalt: mySalt, HMACSalt: mySalt2, handler: myHandler) // GOOD + let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, IV: myConstIV4, encryptionSalt: mySalt, HMACSalt: mySalt2, handler: myHandler) // BAD + + let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, encryptionKey: myKey, hmacKey: myHMACKey, iv: myRandomIV) // GOOD + let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, encryptionKey: myKey, hmacKey: myHMACKey, iv: myConstIV1) // BAD + let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, encryptionKey: myKey, HMACKey: myHMACKey, IV: myRandomIV) // GOOD + let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, encryptionKey: myKey, HMACKey: myHMACKey, IV: myConstIV2) // BAD + let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myPassword, iv: myRandomIV, encryptionSalt: mySalt, hmacSalt: mySalt2) // GOOD + let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myPassword, iv: myConstIV3, encryptionSalt: mySalt, hmacSalt: mySalt2) // BAD + let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, password: myPassword, IV: myRandomIV, encryptionSalt: mySalt, HMACSalt: mySalt2) // GOOD + let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, password: myPassword, IV: myConstIV4, encryptionSalt: mySalt, HMACSalt: mySalt2) // BAD +}