From 987cdff862fdd0dc5d1086b9a60bc08271cdcb33 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 14 Dec 2023 13:56:35 +0000 Subject: [PATCH 1/2] Revert "Revert "Swift: CommonCrypto test cases for the BrokenCryptoAlgorithm query"" This reverts commit a478980e489977b4e6358463f8febd33fa01b7b5. --- .../CWE-327/BrokenCryptoAlgorithm.expected | 0 .../BrokenCryptoAlgorithm.qlref.disabled | 1 + .../Security/CWE-327/test_commoncrypto.swift | 217 ++++++++++++++++++ 3 files changed, 218 insertions(+) create mode 100644 swift/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected create mode 100644 swift/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref.disabled create mode 100644 swift/ql/test/query-tests/Security/CWE-327/test_commoncrypto.swift diff --git a/swift/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected b/swift/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/swift/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref.disabled b/swift/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref.disabled new file mode 100644 index 000000000000..af059fc9e2b8 --- /dev/null +++ b/swift/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref.disabled @@ -0,0 +1 @@ +queries/Security/CWE-327/BrokenCryptoAlgorithm.ql \ No newline at end of file diff --git a/swift/ql/test/query-tests/Security/CWE-327/test_commoncrypto.swift b/swift/ql/test/query-tests/Security/CWE-327/test_commoncrypto.swift new file mode 100644 index 000000000000..499686557fea --- /dev/null +++ b/swift/ql/test/query-tests/Security/CWE-327/test_commoncrypto.swift @@ -0,0 +1,217 @@ +// --- stubs --- + +struct Data { + func withUnsafeBytes( + _ body: (UnsafeRawBufferPointer) throws -> ResultType + ) rethrows -> ResultType { return 0 as! ResultType } + mutating func withUnsafeMutableBytes( + _ body: (UnsafeMutableRawBufferPointer) throws -> ResultType + ) rethrows -> ResultType { return 0 as! ResultType } +} + +// --- CommonCryptor --- +// (real world projects will import the CommonCryptor headers which get +// converted to Swift by the compiler; the following is an approximation +// of that derived from QL queries and the CommonCryptor header files) + +var kCCSuccess : Int = 0 +typealias CCCryptorStatus = Int32 + +typealias CCCryptorRef = OpaquePointer + +var kCCEncrypt : Int = 0 +var kCCDecrypt : Int = 1 +typealias CCOperation = UInt32 + +var kCCAlgorithmAES128 : Int = 0 +var kCCAlgorithmAES : Int = 0 +var kCCAlgorithmDES : Int = 1 +var kCCAlgorithm3DES : Int = 2 +var kCCAlgorithmCAST : Int = 3 +var kCCAlgorithmRC4 : Int = 4 +var kCCAlgorithmRC2 : Int = 5 +var kCCAlgorithmBlowfish : Int = 6 +typealias CCAlgorithm = UInt32 + +var kCCOptionPKCS7Padding : Int = 1 +var kCCOptionECBMode : Int = 2 +typealias CCOptions = UInt32 + +var kCCModeECB : Int = 1 +var kCCModeCBC : Int = 2 +var kCCModeCFB : Int = 3 +var kCCModeCTR : Int = 4 +var kCCModeOFB : Int = 7 +var kCCModeRC4 : Int = 9 +var kCCModeCFB8 : Int = 10 +typealias CCMode = UInt32 + +typealias CCPadding = UInt32 + +typealias CCModeOptions = UInt32 + +func CCCryptorCreate( + _ op: CCOperation, + _ alg: CCAlgorithm, + _ options: CCOptions, + _ key: UnsafeRawPointer?, + _ keyLength: Int, + _ iv: UnsafeRawPointer?, + _ cryptorRef: UnsafeMutablePointer? + ) -> CCCryptorStatus { return 0 } + +func CCCryptorCreateFromData( + _ op: CCOperation, + _ alg: CCAlgorithm, + _ options: CCOptions, + _ key: UnsafeRawPointer?, + _ keyLength: Int, + _ iv: UnsafeRawPointer?, + _ data: UnsafeRawPointer?, + _ dataLength: Int, + _ cryptorRef: UnsafeMutablePointer?, + _ dataUsed: UnsafeMutablePointer? + ) -> CCCryptorStatus { return 0 } + +func CCCryptorCreateWithMode( + _ op: CCOperation, + _ mode: CCMode, + _ alg: CCAlgorithm, + _ padding: CCPadding, + _ iv: UnsafeRawPointer?, + _ key: UnsafeRawPointer?, + _ keyLength: Int, + _ tweak: UnsafeRawPointer?, + _ tweakLength: Int, + _ numRounds: Int32, + _ options: CCModeOptions, + _ cryptorRef: UnsafeMutablePointer? + ) -> CCCryptorStatus { return 0 } + +func CCCryptorUpdate( + _ cryptorRef: CCCryptorRef?, + _ dataIn: UnsafeRawPointer?, + _ dataInLength: Int, + _ dataOut: UnsafeMutableRawPointer?, + _ dataOutAvailable: Int, + _ dataOutMoved: UnsafeMutablePointer? + ) -> CCCryptorStatus { return 0 } + +func CCCryptorFinal( + _ cryptorRef: CCCryptorRef?, + _ dataOut: UnsafeMutableRawPointer?, + _ dataOutAvailable: Int, + _ dataOutMoved: UnsafeMutablePointer? + ) -> CCCryptorStatus { return 0 } + +func CCCrypt( + _ op: CCOperation, + _ alg: CCAlgorithm, + _ options: CCOptions, + _ key: UnsafeRawPointer?, + _ keyLength: Int, + _ iv: UnsafeRawPointer?, + _ dataIn: UnsafeRawPointer?, + _ dataInLength: Int, + _ dataOut: UnsafeMutableRawPointer?, + _ dataOutAvailable: Int, + _ dataOutMoved: UnsafeMutablePointer? + ) -> CCCryptorStatus { return 0 } + +// --- tests --- + +func cond() -> Bool { return true } + +func test_commoncrypto1(key: Data, iv: Data, dataIn: Data, dataOut: inout Data) { + // semi-realistic test case + var myCryptor: CCCryptorRef? + var dataOutWritten = 0 + + key.withUnsafeBytes({ + keyPtr in + iv.withUnsafeBytes({ + // create the cryptor object + ivPtr in + let result1 = CCCryptorCreate( + CCOperation(kCCEncrypt), + CCAlgorithm(kCCAlgorithm3DES), // BAD [NOT DETECTED] + CCOptions(0), + keyPtr.baseAddress!, + keyPtr.count, + ivPtr.baseAddress!, + &myCryptor + ) + guard result1 == CCCryptorStatus(kCCSuccess) else { + return // fail + } + + dataIn.withUnsafeBytes({ + dataInPtr in + dataOut.withUnsafeMutableBytes({ + dataOutPtr in + // encrypt data + while (cond()) { + let result2 = CCCryptorUpdate( + myCryptor, + dataInPtr.baseAddress!, + dataInPtr.count, + dataOutPtr.baseAddress!, + dataOutPtr.count, + &dataOutWritten) + guard result2 == CCCryptorStatus(kCCSuccess) else { + return // fail + } + } + + // finish + let result3 = CCCryptorFinal( + myCryptor, + dataOutPtr.baseAddress!, + dataOutPtr.count, + &dataOutWritten) + guard result3 == CCCryptorStatus(kCCSuccess) else { + return // fail + } + }) + }) + }) + }) +} + +func test_commoncrypto2( + key: UnsafeRawPointer, keyLen: Int, + iv: UnsafeRawPointer, + dataIn: UnsafeRawPointer, dataInLen: Int, + dataOut: UnsafeMutableRawPointer, dataOutAvail: Int) { + var myCryptor: CCCryptorRef? + var dataOutWritten = 0 + + // algorithms + _ = CCCrypt(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmAES128), 0, key, keyLen, iv, dataIn, dataInLen, dataOut, dataOutAvail, nil) + _ = CCCrypt(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmAES), 0, key, keyLen, iv, dataIn, dataInLen, dataOut, dataOutAvail, nil) + _ = CCCrypt(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmDES), 0, key, keyLen, iv, dataIn, dataInLen, dataOut, dataOutAvail, nil) // BAD [NOT DETECTED] + _ = CCCrypt(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithm3DES), 0, key, keyLen, iv, dataIn, dataInLen, dataOut, dataOutAvail, nil) // BAD [NOT DETECTED] + _ = CCCrypt(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmCAST), 0, key, keyLen, iv, dataIn, dataInLen, dataOut, dataOutAvail, nil) + _ = CCCrypt(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmRC4), 0, key, keyLen, iv, dataIn, dataInLen, dataOut, dataOutAvail, nil) // BAD [NOT DETECTED] + _ = CCCrypt(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmRC2), 0, key, keyLen, iv, dataIn, dataInLen, dataOut, dataOutAvail, nil) // BAD [NOT DETECTED] + _ = CCCrypt(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmBlowfish), 0, key, keyLen, iv, dataIn, dataInLen, dataOut, dataOutAvail, nil) + _ = CCCryptorCreate(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithm3DES), 0, key, keyLen, iv, &myCryptor) // BAD [NOT DETECTED] + _ = CCCryptorCreateFromData(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithm3DES), 0, key, keyLen, iv, dataIn, dataInLen, &myCryptor, &dataOutWritten) // BAD [NOT DETECTED] + _ = CCCryptorCreateFromData(CCOperation(kCCDecrypt), CCAlgorithm(kCCAlgorithm3DES), 0, key, keyLen, iv, dataIn, dataInLen, &myCryptor, &dataOutWritten) // BAD [NOT DETECTED] + + // block modes (the default is CBC) + _ = CCCrypt(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmAES), CCOptions(0), key, keyLen, iv, dataIn, dataInLen, dataOut, dataOutAvail, nil) + _ = CCCrypt(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmAES), CCOptions(kCCOptionPKCS7Padding), key, keyLen, iv, dataIn, dataInLen, dataOut, dataOutAvail, nil) + _ = CCCrypt(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmAES), CCOptions(kCCOptionECBMode), key, keyLen, iv, dataIn, dataInLen, dataOut, dataOutAvail, nil) // BAD [NOT DETECTED] + _ = CCCryptorCreate(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithm3DES), CCOptions(kCCOptionECBMode), key, keyLen, iv, &myCryptor) // BAD [NOT DETECTED] + _ = CCCryptorCreateFromData(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithm3DES), CCOptions(kCCOptionECBMode), key, keyLen, iv, dataIn, dataInLen, &myCryptor, &dataOutWritten) // BAD [NOT DETECTED] + + // modes + _ = CCCryptorCreateWithMode(CCOperation(kCCAlgorithmAES), CCMode(kCCModeECB), CCAlgorithm(kCCAlgorithm3DES), CCPadding(0), iv, key, keyLen, nil, 0, 0, CCModeOptions(0), &myCryptor) // BAD [NOT DETECTED] + _ = CCCryptorCreateWithMode(CCOperation(kCCAlgorithmAES), CCMode(kCCModeCBC), CCAlgorithm(kCCAlgorithm3DES), CCPadding(0), iv, key, keyLen, nil, 0, 0, CCModeOptions(0), &myCryptor) + _ = CCCryptorCreateWithMode(CCOperation(kCCAlgorithmAES), CCMode(kCCModeCFB), CCAlgorithm(kCCAlgorithm3DES), CCPadding(0), iv, key, keyLen, nil, 0, 0, CCModeOptions(0), &myCryptor) + _ = CCCryptorCreateWithMode(CCOperation(kCCAlgorithmAES), CCMode(kCCModeCTR), CCAlgorithm(kCCAlgorithm3DES), CCPadding(0), iv, key, keyLen, nil, 0, 0, CCModeOptions(0), &myCryptor) + _ = CCCryptorCreateWithMode(CCOperation(kCCAlgorithmAES), CCMode(kCCModeOFB), CCAlgorithm(kCCAlgorithm3DES), CCPadding(0), iv, key, keyLen, nil, 0, 0, CCModeOptions(0), &myCryptor) + _ = CCCryptorCreateWithMode(CCOperation(kCCAlgorithmAES), CCMode(kCCModeRC4), CCAlgorithm(kCCAlgorithm3DES), CCPadding(0), iv, key, keyLen, nil, 0, 0, CCModeOptions(0), &myCryptor) + _ = CCCryptorCreateWithMode(CCOperation(kCCAlgorithmAES), CCMode(kCCModeCFB8), CCAlgorithm(kCCAlgorithm3DES), CCPadding(0), iv, key, keyLen, nil, 0, 0, CCModeOptions(0), &myCryptor) +} From 7e6ff7c826af9d43614c580d843a9e5f5fe3d797 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 14 Dec 2023 14:09:17 +0000 Subject: [PATCH 2/2] Swift: Disable the part of the test that triggers an extraction issue. --- .../test/query-tests/Security/CWE-327/test_commoncrypto.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swift/ql/test/query-tests/Security/CWE-327/test_commoncrypto.swift b/swift/ql/test/query-tests/Security/CWE-327/test_commoncrypto.swift index 499686557fea..df32d3e477c4 100644 --- a/swift/ql/test/query-tests/Security/CWE-327/test_commoncrypto.swift +++ b/swift/ql/test/query-tests/Security/CWE-327/test_commoncrypto.swift @@ -127,7 +127,7 @@ func test_commoncrypto1(key: Data, iv: Data, dataIn: Data, dataOut: inout Data) var myCryptor: CCCryptorRef? var dataOutWritten = 0 - key.withUnsafeBytes({ + /*key.withUnsafeBytes({ keyPtr in iv.withUnsafeBytes({ // create the cryptor object @@ -175,7 +175,7 @@ func test_commoncrypto1(key: Data, iv: Data, dataIn: Data, dataOut: inout Data) }) }) }) - }) + })*/ } func test_commoncrypto2(