| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- // Alamofire.swift
- //
- // Copyright (c) 2014–2015 Alamofire Software Foundation (http://alamofire.org/)
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- import Foundation
- // TODO: DocStrings
- public class ServerTrustPolicyManager {
- let policies: [String: ServerTrustPolicy]
- // TODO: DocStrings
- public init(policies: [String: ServerTrustPolicy]) {
- self.policies = policies
- }
- func serverTrustPolicyForHost(host: String) -> ServerTrustPolicy? {
- return self.policies[host]
- }
- }
- // MARK: -
- extension NSURLSession {
- private struct AssociatedKeys {
- static var ManagerKey = "NSURLSession.ServerTrustPolicyManager"
- }
- var serverTrustPolicyManager: ServerTrustPolicyManager? {
- get {
- return objc_getAssociatedObject(self, &AssociatedKeys.ManagerKey) as? ServerTrustPolicyManager
- }
- set (manager) {
- objc_setAssociatedObject(self, &AssociatedKeys.ManagerKey, manager, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
- }
- }
- }
- // MARK: - ServerTrustPolicy
- // TODO: DocStrings
- public enum ServerTrustPolicy {
- case PerformDefaultEvaluation(validateHost: Bool)
- case PinCertificates(certificates: [SecCertificate], validateCertificateChain: Bool, validateHost: Bool)
- case PinPublicKeys(publicKeys: [SecKey], validateCertificateChain: Bool, validateHost: Bool)
- case DisableEvaluation
- case CustomEvaluation((serverTrust: SecTrust, host: String) -> Bool)
- // MARK: - Bundle Location
- // TODO: DocStrings
- public func certificatesInBundle(bundle: NSBundle = NSBundle.mainBundle()) -> [SecCertificate] {
- var certificates: [SecCertificate] = []
- for path in bundle.pathsForResourcesOfType(".cer", inDirectory: nil) as! [String] {
- if let
- certificateData = NSData(contentsOfFile: path),
- certificate = SecCertificateCreateWithData(nil, certificateData)?.takeRetainedValue()
- {
- certificates.append(certificate)
- }
- }
- return certificates
- }
- // TODO: DocStrings
- public func publicKeysInBundle(bundle: NSBundle = NSBundle.mainBundle()) -> [SecKey] {
- var publicKeys: [SecKey] = []
- for certificate in certificatesInBundle(bundle: bundle) {
- if let publicKey = publicKeyForCertificate(certificate) {
- publicKeys.append(publicKey)
- }
- }
- return publicKeys
- }
- // MARK: - Evaluation
- // TODO: DocStrings
- public func evaluateServerTrust(serverTrust: SecTrust, isValidForHost host: String) -> Bool {
- var serverTrustIsValid = false
- switch self {
- case let .PerformDefaultEvaluation(validateHost):
- let policy = validateHost ? SecPolicyCreateSSL(1, host as CFString) : SecPolicyCreateBasicX509()
- SecTrustSetPolicies(serverTrust, [policy.takeRetainedValue()])
- serverTrustIsValid = trustIsValid(serverTrust)
- case let .PinCertificates(pinnedCertificates, validateCertificateChain, validateHost):
- if validateCertificateChain {
- let policy = validateHost ? SecPolicyCreateSSL(1, host as CFString) : SecPolicyCreateBasicX509()
- SecTrustSetPolicies(serverTrust, [policy.takeRetainedValue()])
- SecTrustSetAnchorCertificates(serverTrust, pinnedCertificates)
- SecTrustSetAnchorCertificatesOnly(serverTrust, 1)
- serverTrustIsValid = trustIsValid(serverTrust)
- } else {
- let serverCertificatesDataArray = certificateDataForTrust(serverTrust)
- let pinnedCertificatesDataArray = certificateDataForCertificates(pinnedCertificates)
- outerLoop: for serverCertificateData in serverCertificatesDataArray {
- for pinnedCertificateData in pinnedCertificatesDataArray {
- if serverCertificateData.isEqualToData(pinnedCertificateData) {
- serverTrustIsValid = true
- break outerLoop
- }
- }
- }
- }
- case let .PinPublicKeys(pinnedPublicKeys, validateCertificateChain, validateHost):
- var certificateChainEvaluationPassed = true
- if validateCertificateChain {
- let policy = validateHost ? SecPolicyCreateSSL(1, host as CFString) : SecPolicyCreateBasicX509()
- SecTrustSetPolicies(serverTrust, [policy.takeRetainedValue()])
- certificateChainEvaluationPassed = trustIsValid(serverTrust)
- }
- if certificateChainEvaluationPassed {
- let serverKeys = publicKeysForTrust(serverTrust)
- outerLoop: for serverPublicKey in publicKeysForTrust(serverTrust) as [AnyObject] {
- for pinnedPublicKey in pinnedPublicKeys as [AnyObject] {
- if serverPublicKey.isEqual(pinnedPublicKey) {
- serverTrustIsValid = true
- break outerLoop
- }
- }
- }
- }
- case .DisableEvaluation:
- serverTrustIsValid = true
- case let .CustomEvaluation(closure):
- serverTrustIsValid = closure(serverTrust: serverTrust, host: host)
- }
- return serverTrustIsValid
- }
- // MARK: - Private - Trust Validation
- private func trustIsValid(trust: SecTrust) -> Bool {
- var isValid = false
- var result = SecTrustResultType(kSecTrustResultInvalid)
- let status = SecTrustEvaluate(trust, &result)
- if status == errSecSuccess {
- let unspecified = SecTrustResultType(kSecTrustResultUnspecified)
- let proceed = SecTrustResultType(kSecTrustResultProceed)
- isValid = result == unspecified || result == proceed
- }
- return isValid
- }
- // MARK: - Private - Certificate Data
- private func certificateDataForTrust(trust: SecTrust) -> [NSData] {
- var certificates: [SecCertificate] = []
- for index in 0..<SecTrustGetCertificateCount(trust) {
- let certificate = SecTrustGetCertificateAtIndex(trust, index).takeUnretainedValue()
- certificates.append(certificate)
- }
- return certificateDataForCertificates(certificates)
- }
- private func certificateDataForCertificates(certificates: [SecCertificate]) -> [NSData] {
- return certificates.map { SecCertificateCopyData($0).takeRetainedValue() as NSData }
- }
- // MARK: - Private - Public Key Extraction
- private func publicKeysForTrust(trust: SecTrust) -> [SecKey] {
- var publicKeys: [SecKey] = []
- for index in 0..<SecTrustGetCertificateCount(trust) {
- let certificate = SecTrustGetCertificateAtIndex(trust, index).takeUnretainedValue()
- if let publicKey = publicKeyForCertificate(certificate) {
- publicKeys.append(publicKey)
- }
- }
- return publicKeys
- }
- private func publicKeyForCertificate(certificate: SecCertificate) -> SecKey? {
- var publicKey: SecKey?
- let policy = SecPolicyCreateBasicX509().takeRetainedValue()
- var unmanagedTrust: Unmanaged<SecTrust>?
- let trustCreationStatus = SecTrustCreateWithCertificates(certificate, policy, &unmanagedTrust)
- if let trust = unmanagedTrust?.takeRetainedValue() where trustCreationStatus == errSecSuccess {
- publicKey = SecTrustCopyPublicKey(trust).takeRetainedValue()
- }
- return publicKey
- }
- }
|