TLSEvaluationTests.swift 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. //
  2. // TLSEvaluationTests.swift
  3. //
  4. // Copyright (c) 2014-2016 Alamofire Software Foundation (http://alamofire.org/)
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining a copy
  7. // of this software and associated documentation files (the "Software"), to deal
  8. // in the Software without restriction, including without limitation the rights
  9. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. // copies of the Software, and to permit persons to whom the Software is
  11. // furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. // THE SOFTWARE.
  23. //
  24. import Alamofire
  25. import Foundation
  26. import XCTest
  27. private struct TestCertificates {
  28. static let rootCA = TestCertificates.certificate(withFileName: "expired.badssl.com-root-ca")
  29. static let intermediateCA1 = TestCertificates.certificate(withFileName: "expired.badssl.com-intermediate-ca-1")
  30. static let intermediateCA2 = TestCertificates.certificate(withFileName: "expired.badssl.com-intermediate-ca-2")
  31. static let leaf = TestCertificates.certificate(withFileName: "expired.badssl.com-leaf")
  32. static func certificate(withFileName fileName: String) -> SecCertificate {
  33. class Locater {}
  34. let filePath = Bundle(for: Locater.self).path(forResource: fileName, ofType: "cer")!
  35. let data = try! Data(contentsOf: URL(fileURLWithPath: filePath))
  36. let certificate = SecCertificateCreateWithData(nil, data)!
  37. return certificate
  38. }
  39. }
  40. // MARK: -
  41. private struct TestPublicKeys {
  42. static let rootCA = TestPublicKeys.publicKey(for: TestCertificates.rootCA)
  43. static let intermediateCA1 = TestPublicKeys.publicKey(for: TestCertificates.intermediateCA1)
  44. static let intermediateCA2 = TestPublicKeys.publicKey(for: TestCertificates.intermediateCA2)
  45. static let leaf = TestPublicKeys.publicKey(for: TestCertificates.leaf)
  46. static func publicKey(for certificate: SecCertificate) -> SecKey {
  47. let policy = SecPolicyCreateBasicX509()
  48. var trust: SecTrust?
  49. SecTrustCreateWithCertificates(certificate, policy, &trust)
  50. let publicKey = SecTrustCopyPublicKey(trust!)!
  51. return publicKey
  52. }
  53. }
  54. // MARK: -
  55. class TLSEvaluationExpiredLeafCertificateTestCase: BaseTestCase {
  56. let urlString = "https://expired.badssl.com/"
  57. let host = "expired.badssl.com"
  58. var configuration: URLSessionConfiguration!
  59. // MARK: Setup and Teardown
  60. override func setUp() {
  61. super.setUp()
  62. configuration = URLSessionConfiguration.ephemeral
  63. }
  64. // MARK: Default Behavior Tests
  65. func testThatExpiredCertificateRequestFailsWithNoServerTrustPolicy() {
  66. // Given
  67. weak var expectation = self.expectation(description: "\(urlString)")
  68. let manager = SessionManager(configuration: configuration)
  69. var error: NSError?
  70. // When
  71. manager.request(urlString, withMethod: .get)
  72. .response { _, _, _, responseError in
  73. error = responseError
  74. expectation?.fulfill()
  75. }
  76. waitForExpectations(timeout: timeout, handler: nil)
  77. // Then
  78. XCTAssertNotNil(error, "error should not be nil")
  79. if let code = error?.code {
  80. XCTAssertEqual(code, NSURLErrorServerCertificateUntrusted, "code should be untrusted server certficate")
  81. } else {
  82. XCTFail("error should be an NSError")
  83. }
  84. }
  85. // MARK: Server Trust Policy - Perform Default Tests
  86. func testThatExpiredCertificateRequestFailsWithDefaultServerTrustPolicy() {
  87. // Given
  88. let policies = [host: ServerTrustPolicy.performDefaultEvaluation(validateHost: true)]
  89. let manager = SessionManager(
  90. configuration: configuration,
  91. serverTrustPolicyManager: ServerTrustPolicyManager(policies: policies)
  92. )
  93. weak var expectation = self.expectation(description: "\(urlString)")
  94. var error: NSError?
  95. // When
  96. manager.request(urlString, withMethod: .get)
  97. .response { _, _, _, responseError in
  98. error = responseError
  99. expectation?.fulfill()
  100. }
  101. waitForExpectations(timeout: timeout, handler: nil)
  102. // Then
  103. XCTAssertNotNil(error, "error should not be nil")
  104. if let code = error?.code {
  105. XCTAssertEqual(code, NSURLErrorCancelled, "code should be cancelled")
  106. } else {
  107. XCTFail("error should be an NSError")
  108. }
  109. }
  110. // MARK: Server Trust Policy - Certificate Pinning Tests
  111. func testThatExpiredCertificateRequestFailsWhenPinningLeafCertificateWithCertificateChainValidation() {
  112. // Given
  113. let certificates = [TestCertificates.leaf]
  114. let policies: [String: ServerTrustPolicy] = [
  115. host: .pinCertificates(certificates: certificates, validateCertificateChain: true, validateHost: true)
  116. ]
  117. let manager = SessionManager(
  118. configuration: configuration,
  119. serverTrustPolicyManager: ServerTrustPolicyManager(policies: policies)
  120. )
  121. weak var expectation = self.expectation(description: "\(urlString)")
  122. var error: NSError?
  123. // When
  124. manager.request(urlString, withMethod: .get)
  125. .response { _, _, _, responseError in
  126. error = responseError
  127. expectation?.fulfill()
  128. }
  129. waitForExpectations(timeout: timeout, handler: nil)
  130. // Then
  131. XCTAssertNotNil(error, "error should not be nil")
  132. if let code = error?.code {
  133. XCTAssertEqual(code, NSURLErrorCancelled, "code should be cancelled")
  134. } else {
  135. XCTFail("error should be an NSError")
  136. }
  137. }
  138. func testThatExpiredCertificateRequestFailsWhenPinningAllCertificatesWithCertificateChainValidation() {
  139. // Given
  140. let certificates = [
  141. TestCertificates.leaf,
  142. TestCertificates.intermediateCA1,
  143. TestCertificates.intermediateCA2,
  144. TestCertificates.rootCA
  145. ]
  146. let policies: [String: ServerTrustPolicy] = [
  147. host: .pinCertificates(certificates: certificates, validateCertificateChain: true, validateHost: true)
  148. ]
  149. let manager = SessionManager(
  150. configuration: configuration,
  151. serverTrustPolicyManager: ServerTrustPolicyManager(policies: policies)
  152. )
  153. weak var expectation = self.expectation(description: "\(urlString)")
  154. var error: NSError?
  155. // When
  156. manager.request(urlString, withMethod: .get)
  157. .response { _, _, _, responseError in
  158. error = responseError
  159. expectation?.fulfill()
  160. }
  161. waitForExpectations(timeout: timeout, handler: nil)
  162. // Then
  163. XCTAssertNotNil(error, "error should not be nil")
  164. if let code = error?.code {
  165. XCTAssertEqual(code, NSURLErrorCancelled, "code should be cancelled")
  166. } else {
  167. XCTFail("error should be an NSError")
  168. }
  169. }
  170. func testThatExpiredCertificateRequestSucceedsWhenPinningLeafCertificateWithoutCertificateChainValidation() {
  171. // Given
  172. let certificates = [TestCertificates.leaf]
  173. let policies: [String: ServerTrustPolicy] = [
  174. host: .pinCertificates(certificates: certificates, validateCertificateChain: false, validateHost: true)
  175. ]
  176. let manager = SessionManager(
  177. configuration: configuration,
  178. serverTrustPolicyManager: ServerTrustPolicyManager(policies: policies)
  179. )
  180. weak var expectation = self.expectation(description: "\(urlString)")
  181. var error: NSError?
  182. // When
  183. manager.request(urlString, withMethod: .get)
  184. .response { _, _, _, responseError in
  185. error = responseError
  186. expectation?.fulfill()
  187. }
  188. waitForExpectations(timeout: timeout, handler: nil)
  189. // Then
  190. XCTAssertNil(error, "error should be nil")
  191. }
  192. func testThatExpiredCertificateRequestSucceedsWhenPinningIntermediateCACertificateWithoutCertificateChainValidation() {
  193. // Given
  194. let certificates = [TestCertificates.intermediateCA2]
  195. let policies: [String: ServerTrustPolicy] = [
  196. host: .pinCertificates(certificates: certificates, validateCertificateChain: false, validateHost: true)
  197. ]
  198. let manager = SessionManager(
  199. configuration: configuration,
  200. serverTrustPolicyManager: ServerTrustPolicyManager(policies: policies)
  201. )
  202. weak var expectation = self.expectation(description: "\(urlString)")
  203. var error: NSError?
  204. // When
  205. manager.request(urlString, withMethod: .get)
  206. .response { _, _, _, responseError in
  207. error = responseError
  208. expectation?.fulfill()
  209. }
  210. waitForExpectations(timeout: timeout, handler: nil)
  211. // Then
  212. XCTAssertNil(error, "error should be nil")
  213. }
  214. func testThatExpiredCertificateRequestSucceedsWhenPinningRootCACertificateWithoutCertificateChainValidation() {
  215. // Given
  216. let certificates = [TestCertificates.rootCA]
  217. let policies: [String: ServerTrustPolicy] = [
  218. host: .pinCertificates(certificates: certificates, validateCertificateChain: false, validateHost: true)
  219. ]
  220. let manager = SessionManager(
  221. configuration: configuration,
  222. serverTrustPolicyManager: ServerTrustPolicyManager(policies: policies)
  223. )
  224. weak var expectation = self.expectation(description: "\(urlString)")
  225. var error: NSError?
  226. // When
  227. manager.request(urlString, withMethod: .get)
  228. .response { _, _, _, responseError in
  229. error = responseError
  230. expectation?.fulfill()
  231. }
  232. waitForExpectations(timeout: timeout, handler: nil)
  233. // Then
  234. XCTAssertNil(error, "error should be nil")
  235. }
  236. // MARK: Server Trust Policy - Public Key Pinning Tests
  237. func testThatExpiredCertificateRequestFailsWhenPinningLeafPublicKeyWithCertificateChainValidation() {
  238. // Given
  239. let publicKeys = [TestPublicKeys.leaf]
  240. let policies: [String: ServerTrustPolicy] = [
  241. host: .pinPublicKeys(publicKeys: publicKeys, validateCertificateChain: true, validateHost: true)
  242. ]
  243. let manager = SessionManager(
  244. configuration: configuration,
  245. serverTrustPolicyManager: ServerTrustPolicyManager(policies: policies)
  246. )
  247. weak var expectation = self.expectation(description: "\(urlString)")
  248. var error: NSError?
  249. // When
  250. manager.request(urlString, withMethod: .get)
  251. .response { _, _, _, responseError in
  252. error = responseError
  253. expectation?.fulfill()
  254. }
  255. waitForExpectations(timeout: timeout, handler: nil)
  256. // Then
  257. XCTAssertNotNil(error, "error should not be nil")
  258. if let code = error?.code {
  259. XCTAssertEqual(code, NSURLErrorCancelled, "code should be cancelled")
  260. } else {
  261. XCTFail("error should be an NSError")
  262. }
  263. }
  264. func testThatExpiredCertificateRequestSucceedsWhenPinningLeafPublicKeyWithoutCertificateChainValidation() {
  265. // Given
  266. let publicKeys = [TestPublicKeys.leaf]
  267. let policies: [String: ServerTrustPolicy] = [
  268. host: .pinPublicKeys(publicKeys: publicKeys, validateCertificateChain: false, validateHost: true)
  269. ]
  270. let manager = SessionManager(
  271. configuration: configuration,
  272. serverTrustPolicyManager: ServerTrustPolicyManager(policies: policies)
  273. )
  274. weak var expectation = self.expectation(description: "\(urlString)")
  275. var error: NSError?
  276. // When
  277. manager.request(urlString, withMethod: .get)
  278. .response { _, _, _, responseError in
  279. error = responseError
  280. expectation?.fulfill()
  281. }
  282. waitForExpectations(timeout: timeout, handler: nil)
  283. // Then
  284. XCTAssertNil(error, "error should be nil")
  285. }
  286. func testThatExpiredCertificateRequestSucceedsWhenPinningIntermediateCAPublicKeyWithoutCertificateChainValidation() {
  287. // Given
  288. let publicKeys = [TestPublicKeys.intermediateCA2]
  289. let policies: [String: ServerTrustPolicy] = [
  290. host: .pinPublicKeys(publicKeys: publicKeys, validateCertificateChain: false, validateHost: true)
  291. ]
  292. let manager = SessionManager(
  293. configuration: configuration,
  294. serverTrustPolicyManager: ServerTrustPolicyManager(policies: policies)
  295. )
  296. weak var expectation = self.expectation(description: "\(urlString)")
  297. var error: NSError?
  298. // When
  299. manager.request(urlString, withMethod: .get)
  300. .response { _, _, _, responseError in
  301. error = responseError
  302. expectation?.fulfill()
  303. }
  304. waitForExpectations(timeout: timeout, handler: nil)
  305. // Then
  306. XCTAssertNil(error, "error should be nil")
  307. }
  308. func testThatExpiredCertificateRequestSucceedsWhenPinningRootCAPublicKeyWithoutCertificateChainValidation() {
  309. // Given
  310. let publicKeys = [TestPublicKeys.rootCA]
  311. let policies: [String: ServerTrustPolicy] = [
  312. host: .pinPublicKeys(publicKeys: publicKeys, validateCertificateChain: false, validateHost: true)
  313. ]
  314. let manager = SessionManager(
  315. configuration: configuration,
  316. serverTrustPolicyManager: ServerTrustPolicyManager(policies: policies)
  317. )
  318. weak var expectation = self.expectation(description: "\(urlString)")
  319. var error: NSError?
  320. // When
  321. manager.request(urlString, withMethod: .get)
  322. .response { _, _, _, responseError in
  323. error = responseError
  324. expectation?.fulfill()
  325. }
  326. waitForExpectations(timeout: timeout, handler: nil)
  327. // Then
  328. XCTAssertNil(error, "error should be nil")
  329. }
  330. // MARK: Server Trust Policy - Disabling Evaluation Tests
  331. func testThatExpiredCertificateRequestSucceedsWhenDisablingEvaluation() {
  332. // Given
  333. let policies = [host: ServerTrustPolicy.disableEvaluation]
  334. let manager = SessionManager(
  335. configuration: configuration,
  336. serverTrustPolicyManager: ServerTrustPolicyManager(policies: policies)
  337. )
  338. weak var expectation = self.expectation(description: "\(urlString)")
  339. var error: NSError?
  340. // When
  341. manager.request(urlString, withMethod: .get)
  342. .response { _, _, _, responseError in
  343. error = responseError
  344. expectation?.fulfill()
  345. }
  346. waitForExpectations(timeout: timeout, handler: nil)
  347. // Then
  348. XCTAssertNil(error, "error should be nil")
  349. }
  350. // MARK: Server Trust Policy - Custom Evaluation Tests
  351. func testThatExpiredCertificateRequestSucceedsWhenCustomEvaluationReturnsTrue() {
  352. // Given
  353. let policies = [
  354. host: ServerTrustPolicy.customEvaluation { _, _ in
  355. // Implement a custom evaluation routine here...
  356. return true
  357. }
  358. ]
  359. let manager = SessionManager(
  360. configuration: configuration,
  361. serverTrustPolicyManager: ServerTrustPolicyManager(policies: policies)
  362. )
  363. weak var expectation = self.expectation(description: "\(urlString)")
  364. var error: NSError?
  365. // When
  366. manager.request(urlString, withMethod: .get)
  367. .response { _, _, _, responseError in
  368. error = responseError
  369. expectation?.fulfill()
  370. }
  371. waitForExpectations(timeout: timeout, handler: nil)
  372. // Then
  373. XCTAssertNil(error, "error should be nil")
  374. }
  375. func testThatExpiredCertificateRequestFailsWhenCustomEvaluationReturnsFalse() {
  376. // Given
  377. let policies = [
  378. host: ServerTrustPolicy.customEvaluation { _, _ in
  379. // Implement a custom evaluation routine here...
  380. return false
  381. }
  382. ]
  383. let manager = SessionManager(
  384. configuration: configuration,
  385. serverTrustPolicyManager: ServerTrustPolicyManager(policies: policies)
  386. )
  387. weak var expectation = self.expectation(description: "\(urlString)")
  388. var error: NSError?
  389. // When
  390. manager.request(urlString, withMethod: .get)
  391. .response { _, _, _, responseError in
  392. error = responseError
  393. expectation?.fulfill()
  394. }
  395. waitForExpectations(timeout: timeout, handler: nil)
  396. // Then
  397. XCTAssertNotNil(error, "error should not be nil")
  398. if let code = error?.code {
  399. XCTAssertEqual(code, NSURLErrorCancelled, "code should be cancelled")
  400. } else {
  401. XCTFail("error should be an NSError")
  402. }
  403. }
  404. }