2
0

ServerTrustEvaluation.swift 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. //
  2. // ServerTrustPolicy.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 Foundation
  25. /// Responsible for managing the mapping of `ServerTrustEvaluating` values to given hosts.
  26. open class ServerTrustManager {
  27. /// Determines whether all hosts for this `ServerTrustManager` must be evaluated. `true` by default.
  28. public let allHostsMustBeEvaluated: Bool
  29. /// The dictionary of policies mapped to a particular host.
  30. public let evaluators: [String: ServerTrustEvaluating]
  31. /// Initializes the `ServerTrustManager` instance with the given evaluators.
  32. ///
  33. /// Since different servers and web services can have different leaf certificates, intermediate and even root
  34. /// certificates, it is important to have the flexibility to specify evaluation policies on a per host basis. This
  35. /// allows for scenarios such as using default evaluation for host1, certificate pinning for host2, public key
  36. /// pinning for host3 and disabling evaluation for host4.
  37. ///
  38. /// - Parameters:
  39. /// - allHostsMustBeEvaluated: The value determining whether all hosts for this instance must be evaluated. `true`
  40. /// by default.
  41. /// - evaluators: A dictionary of evaluators mapped to hosts.
  42. public init(allHostsMustBeEvaluated: Bool = true, evaluators: [String: ServerTrustEvaluating]) {
  43. self.allHostsMustBeEvaluated = allHostsMustBeEvaluated
  44. self.evaluators = evaluators
  45. }
  46. /// Returns the `ServerTrustEvaluating` value for the given host, if one is set.
  47. ///
  48. /// By default, this method will return the policy that perfectly matches the given host. Subclasses could override
  49. /// this method and implement more complex mapping implementations such as wildcards.
  50. ///
  51. /// - Parameter host: The host to use when searching for a matching policy.
  52. ///
  53. /// - Returns: The `ServerTrustEvaluating` value for the given host if found, `nil` otherwise.
  54. /// - Throws: `AFError.serverTrustEvaluationFailed` if `allHostsMustBeEvaluated` is `true` and no matching
  55. /// evaluators are found.
  56. open func serverTrustEvaluator(forHost host: String) throws -> ServerTrustEvaluating? {
  57. guard let evaluator = evaluators[host] else {
  58. if allHostsMustBeEvaluated {
  59. throw AFError.serverTrustEvaluationFailed(reason: .noRequiredEvaluator(host: host))
  60. }
  61. return nil
  62. }
  63. return evaluator
  64. }
  65. }
  66. /// A protocol describing the API used to evaluate server trusts.
  67. public protocol ServerTrustEvaluating {
  68. #if os(Linux)
  69. // Implement this once Linux has API for evaluating server trusts.
  70. #else
  71. /// Evaluates the given `SecTrust` value for the given `host`.
  72. ///
  73. /// - Parameters:
  74. /// - trust: The `SecTrust` value to evaluate.
  75. /// - host: The host for which to evaluate the `SecTrust` value.
  76. ///
  77. /// - Returns: A `Bool` indicating whether the evaluator considers the `SecTrust` value valid for `host`.
  78. func evaluate(_ trust: SecTrust, forHost host: String) throws
  79. #endif
  80. }
  81. // MARK: - Server Trust Evaluators
  82. /// An evaluator which uses the default server trust evaluation while allowing you to control whether to validate the
  83. /// host provided by the challenge. Applications are encouraged to always validate the host in production environments
  84. /// to guarantee the validity of the server's certificate chain.
  85. public final class DefaultTrustEvaluator: ServerTrustEvaluating {
  86. private let validateHost: Bool
  87. /// Creates a `DefaultTrustEvaluator`.
  88. ///
  89. /// - Parameter validateHost: Determines whether or not the evaluator should validate the host. `true` by default.
  90. public init(validateHost: Bool = true) {
  91. self.validateHost = validateHost
  92. }
  93. public func evaluate(_ trust: SecTrust, forHost host: String) throws {
  94. if validateHost {
  95. try trust.af.performValidation(forHost: host)
  96. }
  97. try trust.af.performDefaultValidation(forHost: host)
  98. }
  99. }
  100. /// An evaluator which Uses the default and revoked server trust evaluations allowing you to control whether to validate
  101. /// the host provided by the challenge as well as specify the revocation flags for testing for revoked certificates.
  102. /// Apple platforms did not start testing for revoked certificates automatically until iOS 10.1, macOS 10.12 and tvOS
  103. /// 10.1 which is demonstrated in our TLS tests. Applications are encouraged to always validate the host in production
  104. /// environments to guarantee the validity of the server's certificate chain.
  105. public final class RevocationTrustEvaluator: ServerTrustEvaluating {
  106. /// Represents the options to be use when evaluating the status of a certificate.
  107. /// Only Revocation Policy Constants are valid, and can be found in [Apple's documentation](https://developer.apple.com/documentation/security/certificate_key_and_trust_services/policies/1563600-revocation_policy_constants).
  108. public struct Options: OptionSet {
  109. /// Perform revocation checking using the CRL (Certification Revocation List) method.
  110. public static let crl = Options(rawValue: kSecRevocationCRLMethod)
  111. /// Consult only locally cached replies; do not use network access.
  112. public static let networkAccessDisabled = Options(rawValue: kSecRevocationNetworkAccessDisabled)
  113. /// Perform revocation checking using OCSP (Online Certificate Status Protocol).
  114. public static let ocsp = Options(rawValue: kSecRevocationOCSPMethod)
  115. /// Prefer CRL revocation checking over OCSP; by default, OCSP is preferred.
  116. public static let preferCRL = Options(rawValue: kSecRevocationPreferCRL)
  117. /// Require a positive response to pass the policy. If the flag is not set, revocation checking is done on a
  118. /// "best attempt" basis, where failure to reach the server is not considered fatal.
  119. public static let requirePositiveResponse = Options(rawValue: kSecRevocationRequirePositiveResponse)
  120. /// Perform either OCSP or CRL checking. The checking is performed according to the method(s) specified in the
  121. /// certificate and the value of `preferCRL`.
  122. public static let any = Options(rawValue: kSecRevocationUseAnyAvailableMethod)
  123. /// The raw value of the option.
  124. public let rawValue: CFOptionFlags
  125. /// Creates an `Options` value with the given `CFOptionFlags`.
  126. ///
  127. /// - Parameter rawValue: The `CFOptionFlags` value to initialize with.
  128. public init(rawValue: CFOptionFlags) {
  129. self.rawValue = rawValue
  130. }
  131. }
  132. private let performDefaultValidation: Bool
  133. private let validateHost: Bool
  134. private let options: Options
  135. /// Creates a `RevocationTrustEvaluator`.
  136. ///
  137. /// - Note: Default and host validation will fail when using this evaluator with self-signed certificates. Use
  138. /// `PinnedCertificatesTrustEvaluator` if you need to use self-signed certificates.
  139. ///
  140. /// - Parameters:
  141. /// - performDefaultValidation: Determines whether default validation should be performed in addition to
  142. /// evaluating the pinned certificates. `true` by default.
  143. /// - validateHost: Determines whether or not the evaluator should validate the host, in addition
  144. /// to performing the default evaluation, even if `performDefaultValidation` is
  145. /// `false`. `true` by default.
  146. /// - options: The `Options` to use to check the revocation status of the certificate. `.any`
  147. /// by default.
  148. public init(performDefaultValidation: Bool = true, validateHost: Bool = true, options: Options = .any) {
  149. self.performDefaultValidation = performDefaultValidation
  150. self.validateHost = validateHost
  151. self.options = options
  152. }
  153. public func evaluate(_ trust: SecTrust, forHost host: String) throws {
  154. if performDefaultValidation {
  155. try trust.af.performDefaultValidation(forHost: host)
  156. }
  157. if validateHost {
  158. try trust.af.performValidation(forHost: host)
  159. }
  160. try trust.af.validate(policy: SecPolicy.af.revocation(options: options)) { status, result in
  161. AFError.serverTrustEvaluationFailed(reason: .revocationCheckFailed(output: .init(host, trust, status, result), options: options))
  162. }
  163. }
  164. }
  165. /// Uses the pinned certificates to validate the server trust. The server trust is considered valid if one of the pinned
  166. /// certificates match one of the server certificates. By validating both the certificate chain and host, certificate
  167. /// pinning provides a very secure form of server trust validation mitigating most, if not all, MITM attacks.
  168. /// Applications are encouraged to always validate the host and require a valid certificate chain in production
  169. /// environments.
  170. public final class PinnedCertificatesTrustEvaluator: ServerTrustEvaluating {
  171. private let certificates: [SecCertificate]
  172. private let acceptSelfSignedCertificates: Bool
  173. private let performDefaultValidation: Bool
  174. private let validateHost: Bool
  175. /// Creates a `PinnedCertificatesTrustEvaluator`.
  176. ///
  177. /// - Parameters:
  178. /// - certificates: The certificates to use to evaluate the trust. All `cer`, `crt`, and `der`
  179. /// certificates in `Bundle.main` by default.
  180. /// - acceptSelfSignedCertificates: Adds the provided certificates as anchors for the trust evaluation, allowing
  181. /// self-signed certificates to pass. `false` by default. THIS SETTING SHOULD BE
  182. /// FALSE IN PRODUCTION!
  183. /// - performDefaultValidation: Determines whether default validation should be performed in addition to
  184. /// evaluating the pinned certificates. `true` by default.
  185. /// - validateHost: Determines whether or not the evaluator should validate the host, in addition
  186. /// to performing the default evaluation, even if `performDefaultValidation` is
  187. /// `false`. `true` by default.
  188. public init(certificates: [SecCertificate] = Bundle.main.af.certificates,
  189. acceptSelfSignedCertificates: Bool = false,
  190. performDefaultValidation: Bool = true,
  191. validateHost: Bool = true) {
  192. self.certificates = certificates
  193. self.acceptSelfSignedCertificates = acceptSelfSignedCertificates
  194. self.performDefaultValidation = performDefaultValidation
  195. self.validateHost = validateHost
  196. }
  197. public func evaluate(_ trust: SecTrust, forHost host: String) throws {
  198. guard !certificates.isEmpty else {
  199. throw AFError.serverTrustEvaluationFailed(reason: .noCertificatesFound)
  200. }
  201. if acceptSelfSignedCertificates {
  202. try trust.af.setAnchorCertificates(certificates)
  203. }
  204. if performDefaultValidation {
  205. try trust.af.performDefaultValidation(forHost: host)
  206. }
  207. if validateHost {
  208. try trust.af.performValidation(forHost: host)
  209. }
  210. let serverCertificatesData = Set(trust.af.certificateData)
  211. let pinnedCertificatesData = Set(certificates.af.data)
  212. let pinnedCertificatesInServerData = !serverCertificatesData.isDisjoint(with: pinnedCertificatesData)
  213. if !pinnedCertificatesInServerData {
  214. throw AFError.serverTrustEvaluationFailed(reason: .certificatePinningFailed(host: host,
  215. trust: trust,
  216. pinnedCertificates: certificates,
  217. serverCertificates: trust.af.certificates))
  218. }
  219. }
  220. }
  221. /// Uses the pinned public keys to validate the server trust. The server trust is considered valid if one of the pinned
  222. /// public keys match one of the server certificate public keys. By validating both the certificate chain and host,
  223. /// public key pinning provides a very secure form of server trust validation mitigating most, if not all, MITM attacks.
  224. /// Applications are encouraged to always validate the host and require a valid certificate chain in production
  225. /// environments.
  226. public final class PublicKeysTrustEvaluator: ServerTrustEvaluating {
  227. private let keys: [SecKey]
  228. private let performDefaultValidation: Bool
  229. private let validateHost: Bool
  230. /// Creates a `PublicKeysTrustEvaluator`.
  231. ///
  232. /// - Note: Default and host validation will fail when using this evaluator with self-signed certificates. Use
  233. /// `PinnedCertificatesTrustEvaluator` if you need to use self-signed certificates.
  234. ///
  235. /// - Parameters:
  236. /// - keys: The `SecKey`s to use to validate public keys. Defaults to the public keys of all
  237. /// certificates included in the main bundle.
  238. /// - performDefaultValidation: Determines whether default validation should be performed in addition to
  239. /// evaluating the pinned certificates. `true` by default.
  240. /// - validateHost: Determines whether or not the evaluator should validate the host, in addition to
  241. /// performing the default evaluation, even if `performDefaultValidation` is `false`.
  242. /// `true` by default.
  243. public init(keys: [SecKey] = Bundle.main.af.publicKeys,
  244. performDefaultValidation: Bool = true,
  245. validateHost: Bool = true) {
  246. self.keys = keys
  247. self.performDefaultValidation = performDefaultValidation
  248. self.validateHost = validateHost
  249. }
  250. public func evaluate(_ trust: SecTrust, forHost host: String) throws {
  251. guard !keys.isEmpty else {
  252. throw AFError.serverTrustEvaluationFailed(reason: .noPublicKeysFound)
  253. }
  254. if performDefaultValidation {
  255. try trust.af.performDefaultValidation(forHost: host)
  256. }
  257. if validateHost {
  258. try trust.af.performValidation(forHost: host)
  259. }
  260. let pinnedKeysInServerKeys: Bool = {
  261. for serverPublicKey in trust.af.publicKeys {
  262. for pinnedPublicKey in keys {
  263. if serverPublicKey == pinnedPublicKey {
  264. return true
  265. }
  266. }
  267. }
  268. return false
  269. }()
  270. if !pinnedKeysInServerKeys {
  271. throw AFError.serverTrustEvaluationFailed(reason: .publicKeyPinningFailed(host: host,
  272. trust: trust,
  273. pinnedKeys: keys,
  274. serverKeys: trust.af.publicKeys))
  275. }
  276. }
  277. }
  278. /// Uses the provided evaluators to validate the server trust. The trust is only considered valid if all of the
  279. /// evaluators consider it valid.
  280. public final class CompositeTrustEvaluator: ServerTrustEvaluating {
  281. private let evaluators: [ServerTrustEvaluating]
  282. /// Creates a `CompositeTrustEvaluator`.
  283. ///
  284. /// - Parameter evaluators: The `ServerTrustEvaluating` values used to evaluate the server trust.
  285. public init(evaluators: [ServerTrustEvaluating]) {
  286. self.evaluators = evaluators
  287. }
  288. public func evaluate(_ trust: SecTrust, forHost host: String) throws {
  289. try evaluators.evaluate(trust, forHost: host)
  290. }
  291. }
  292. /// Disables all evaluation which in turn will always consider any server trust as valid.
  293. ///
  294. /// **THIS EVALUATOR SHOULD NEVER BE USED IN PRODUCTION!**
  295. public final class DisabledEvaluator: ServerTrustEvaluating {
  296. /// Creates an instance.
  297. public init() {}
  298. public func evaluate(_ trust: SecTrust, forHost host: String) throws {}
  299. }
  300. // MARK: - Extensions
  301. public extension Array where Element == ServerTrustEvaluating {
  302. #if os(Linux)
  303. // Add this same convenience method for Linux.
  304. #else
  305. /// Evaluates the given `SecTrust` value for the given `host`.
  306. ///
  307. /// - Parameters:
  308. /// - trust: The `SecTrust` value to evaluate.
  309. /// - host: The host for which to evaluate the `SecTrust` value.
  310. ///
  311. /// - Returns: Whether or not the evaluator considers the `SecTrust` value valid for `host`.
  312. func evaluate(_ trust: SecTrust, forHost host: String) throws {
  313. for evaluator in self {
  314. try evaluator.evaluate(trust, forHost: host)
  315. }
  316. }
  317. #endif
  318. }
  319. extension Bundle: AlamofireExtended {}
  320. public extension AlamofireExtension where ExtendedType: Bundle {
  321. /// Returns all valid `cer`, `crt`, and `der` certificates in the bundle.
  322. var certificates: [SecCertificate] {
  323. return paths(forResourcesOfTypes: [".cer", ".CER", ".crt", ".CRT", ".der", ".DER"]).compactMap { path in
  324. guard
  325. let certificateData = try? Data(contentsOf: URL(fileURLWithPath: path)) as CFData,
  326. let certificate = SecCertificateCreateWithData(nil, certificateData) else { return nil }
  327. return certificate
  328. }
  329. }
  330. /// Returns all public keys for the valid certificates in the bundle.
  331. var publicKeys: [SecKey] {
  332. return certificates.af.publicKeys
  333. }
  334. /// Returns all pathnames for the resources identified by the provided file extensions.
  335. ///
  336. /// - Parameter types: The filename extensions locate.
  337. ///
  338. /// - Returns: All pathnames for the given filename extensions.
  339. func paths(forResourcesOfTypes types: [String]) -> [String] {
  340. return Array(Set(types.flatMap { type.paths(forResourcesOfType: $0, inDirectory: nil) }))
  341. }
  342. }
  343. extension SecTrust: AlamofireExtended {}
  344. public extension AlamofireExtension where ExtendedType == SecTrust {
  345. /// Attempts to validate `self` using the policy provided and transforming any error produced using the closure passed.
  346. ///
  347. /// - Parameters:
  348. /// - policy: The `SecPolicy` used to evaluate `self`.
  349. /// - errorProducer: The closure used transform the failed `OSStatus` and `SecTrustResultType`.
  350. /// - Throws: Any error from applying the `policy`, or the result of `errorProducer` if validation fails.
  351. func validate(policy: SecPolicy, errorProducer: (_ status: OSStatus, _ result: SecTrustResultType) -> Error) throws {
  352. try apply(policy: policy).af.validate(errorProducer: errorProducer)
  353. }
  354. /// Applies a `SecPolicy` to `self`, throwing if it fails.
  355. ///
  356. /// - Parameter policy: The `SecPolicy`.
  357. ///
  358. /// - Returns: `self`, with the policy applied.
  359. /// - Throws: An `AFError.serverTrustEvaluationFailed` instance with a `.policyApplicationFailed` reason.
  360. func apply(policy: SecPolicy) throws -> SecTrust {
  361. let status = SecTrustSetPolicies(type, policy)
  362. guard status.af.isSuccess else {
  363. throw AFError.serverTrustEvaluationFailed(reason: .policyApplicationFailed(trust: type,
  364. policy: policy,
  365. status: status))
  366. }
  367. return type
  368. }
  369. /// Validate `self`, passing any failure values through `errorProducer`.
  370. ///
  371. /// - Parameter errorProducer: The closure used to transform the failed `OSStatus` and `SecTrustResultType` into an
  372. /// `Error`.
  373. /// - Throws: The `Error` produced by the `errorProducer` closure.
  374. func validate(errorProducer: (_ status: OSStatus, _ result: SecTrustResultType) -> Error) throws {
  375. var result = SecTrustResultType.invalid
  376. let status = SecTrustEvaluate(type, &result)
  377. guard status.af.isSuccess && result.af.isSuccess else {
  378. throw errorProducer(status, result)
  379. }
  380. }
  381. /// Sets a custom certificate chain on `self`, allowing full validation of a self-signed certificate and its chain.
  382. ///
  383. /// - Parameter certificates: The `SecCertificate`s to add to the chain.
  384. /// - Throws: Any error produced when applying the new certificate chain.
  385. func setAnchorCertificates(_ certificates: [SecCertificate]) throws {
  386. // Add additional anchor certificates.
  387. let status = SecTrustSetAnchorCertificates(type, certificates as CFArray)
  388. guard status.af.isSuccess else {
  389. throw AFError.serverTrustEvaluationFailed(reason: .settingAnchorCertificatesFailed(status: status,
  390. certificates: certificates))
  391. }
  392. // Reenable system anchor certificates.
  393. let systemStatus = SecTrustSetAnchorCertificatesOnly(type, true)
  394. guard systemStatus.af.isSuccess else {
  395. throw AFError.serverTrustEvaluationFailed(reason: .settingAnchorCertificatesFailed(status: systemStatus,
  396. certificates: certificates))
  397. }
  398. }
  399. /// The public keys contained in `self`.
  400. var publicKeys: [SecKey] {
  401. return certificates.af.publicKeys
  402. }
  403. /// The `SecCertificate`s contained i `self`.
  404. var certificates: [SecCertificate] {
  405. return (0..<SecTrustGetCertificateCount(type)).compactMap { index in
  406. SecTrustGetCertificateAtIndex(type, index)
  407. }
  408. }
  409. /// The `Data` values for all certificates contained in `self`.
  410. var certificateData: [Data] {
  411. return certificates.af.data
  412. }
  413. /// Validates `self` after applying `SecPolicy.af.default`. This evaluation does not validate the hostname.
  414. ///
  415. /// - Parameter host: The hostname, used only in the error output if validation fails.
  416. /// - Throws: An `AFError.serverTrustEvaluationFailed` instance with a `.defaultEvaluationFailed` reason.
  417. func performDefaultValidation(forHost host: String) throws {
  418. try validate(policy: SecPolicy.af.default) { status, result in
  419. AFError.serverTrustEvaluationFailed(reason: .defaultEvaluationFailed(output: .init(host, type, status, result)))
  420. }
  421. }
  422. /// Validates `self` after applying `SecPolicy.af.hostname(host)`, which performs the default validation as well as
  423. /// hostname validation.
  424. ///
  425. /// - Parameter host: The hostname to use in the validation.
  426. /// - Throws: An `AFError.serverTrustEvaluationFailed` instance with a `.defaultEvaluationFailed` reason.
  427. func performValidation(forHost host: String) throws {
  428. try validate(policy: SecPolicy.af.hostname(host)) { status, result in
  429. AFError.serverTrustEvaluationFailed(reason: .hostValidationFailed(output: .init(host, type, status, result)))
  430. }
  431. }
  432. }
  433. extension SecPolicy: AlamofireExtended {}
  434. public extension AlamofireExtension where ExtendedType == SecPolicy {
  435. /// Creates a `SecPolicy` instance which will validate server certificates but not require a host name match.
  436. static let `default` = SecPolicyCreateSSL(true, nil)
  437. /// Creates a `SecPolicy` instance which will validate server certificates and much match the provided hostname.
  438. ///
  439. /// - Parameter hostname: The hostname to validate against.
  440. ///
  441. /// - Returns: The `SecPolicy`.
  442. static func hostname(_ hostname: String) -> SecPolicy {
  443. return SecPolicyCreateSSL(true, hostname as CFString)
  444. }
  445. /// Creates a `SecPolicy` which checks the revocation of certificates.
  446. ///
  447. /// - Parameter options: The `RevocationTrustEvaluator.Options` for evaluation.
  448. ///
  449. /// - Returns: The `SecPolicy`.
  450. /// - Throws: An `AFError.serverTrustEvaluationFailed` error with reason `.revocationPolicyCreationFailed`
  451. /// if the policy cannot be created.
  452. static func revocation(options: RevocationTrustEvaluator.Options) throws -> SecPolicy {
  453. guard let policy = SecPolicyCreateRevocation(options.rawValue) else {
  454. throw AFError.serverTrustEvaluationFailed(reason: .revocationPolicyCreationFailed)
  455. }
  456. return policy
  457. }
  458. }
  459. extension Array: AlamofireExtended {}
  460. public extension AlamofireExtension where ExtendedType == [SecCertificate] {
  461. /// All `Data` values for the contained `SecCertificate`s.
  462. var data: [Data] {
  463. return type.map { SecCertificateCopyData($0) as Data }
  464. }
  465. /// All public `SecKey` values for the contained `SecCertificate`s.
  466. var publicKeys: [SecKey] {
  467. return type.compactMap { $0.af.publicKey }
  468. }
  469. }
  470. extension SecCertificate: AlamofireExtended {}
  471. public extension AlamofireExtension where ExtendedType == SecCertificate {
  472. /// The public key for `self`, if it can be extracted.
  473. var publicKey: SecKey? {
  474. let policy = SecPolicyCreateBasicX509()
  475. var trust: SecTrust?
  476. let trustCreationStatus = SecTrustCreateWithCertificates(type, policy, &trust)
  477. guard let createdTrust = trust, trustCreationStatus == errSecSuccess else { return nil }
  478. return SecTrustCopyPublicKey(createdTrust)
  479. }
  480. }
  481. extension OSStatus: AlamofireExtended {}
  482. public extension AlamofireExtension where ExtendedType == OSStatus {
  483. /// Returns whether `self` is `errSecSuccess`.
  484. var isSuccess: Bool { return type == errSecSuccess }
  485. }
  486. extension SecTrustResultType: AlamofireExtended {}
  487. public extension AlamofireExtension where ExtendedType == SecTrustResultType {
  488. /// Returns whether `self is `.unspecified` or `.proceed`.
  489. var isSuccess: Bool {
  490. return (type == .unspecified || type == .proceed)
  491. }
  492. }