0001    // ServerTrustPolicy.swift
0002    //
0003    // Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
0004    //
0005    // Permission is hereby granted, free of charge, to any person obtaining a copy
0006    // of this software and associated documentation files (the "Software"), to deal
0007    // in the Software without restriction, including without limitation the rights
0008    // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
0009    // copies of the Software, and to permit persons to whom the Software is
0010    // furnished to do so, subject to the following conditions:
0011    //
0012    // The above copyright notice and this permission notice shall be included in
0013    // all copies or substantial portions of the Software.
0014    //
0015    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0016    // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0017    // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0018    // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0019    // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
0020    // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
0021    // THE SOFTWARE.
0022    
0023    import Foundation
0024    
0025    /// Responsible for managing the mapping of `ServerTrustPolicy` objects to a given host.
0026    public class ServerTrustPolicyManager
Manager.swift:123
        serverTrustPolicyManager: ServerTrustPolicyManager? = nil)
Manager.swift:144
        serverTrustPolicyManager: ServerTrustPolicyManager? = nil)
Manager.swift:154
    private func commonInit(serverTrustPolicyManager serverTrustPolicyManager: ServerTrustPolicyManager?) {
ServerTrustPolicy.swift:70
            return objc_getAssociatedObject(self, &AssociatedKeys.ManagerKey) as? ServerTrustPolicyManager
ServerTrustPolicy.swift:68
    var serverTrustPolicyManager: ServerTrustPolicyManager? {
{ 0027 /// The dictionary of policies mapped to a particular host. 0028 public let policies
ServerTrustPolicy.swift:43
        self.policies = policies
ServerTrustPolicy.swift:57
        return policies[host]
: [String: ServerTrustPolicy] 0029 0030 /** 0031 Initializes the `ServerTrustPolicyManager` instance with the given policies. 0032 0033 Since different servers and web services can have different leaf certificates, intermediate and even root 0034 certficates, it is important to have the flexibility to specify evaluation policies on a per host basis. This 0035 allows for scenarios such as using default evaluation for host1, certificate pinning for host2, public key 0036 pinning for host3 and disabling evaluation for host4. 0037 0038 - parameter policies: A dictionary of all policies mapped to a particular host. 0039 0040 - returns: The new `ServerTrustPolicyManager` instance. 0041 */ 0042 public init(policies: [String: ServerTrustPolicy]) { 0043 self.policies = policies 0044 } 0045 0046 /** 0047 Returns the `ServerTrustPolicy` for the given host if applicable. 0048 0049 By default, this method will return the policy that perfectly matches the given host. Subclasses could override 0050 this method and implement more complex mapping implementations such as wildcards. 0051 0052 - parameter host: The host to use when searching for a matching policy. 0053 0054 - returns: The server trust policy for the given host if found. 0055 */ 0056 public func serverTrustPolicyForHost
Manager.swift:293
                    serverTrustPolicy = session.serverTrustPolicyManager?.serverTrustPolicyForHost(host),
Request.swift:275
                    serverTrustPolicy = session.serverTrustPolicyManager?.serverTrustPolicyForHost(host),
(host: String) -> ServerTrustPolicy? { 0057 return policies[host] 0058 } 0059 } 0060 0061 // MARK: - 0062 0063 extension NSURLSession { 0064 private struct AssociatedKeys
ServerTrustPolicy.swift:70
            return objc_getAssociatedObject(self, &AssociatedKeys.ManagerKey) as? ServerTrustPolicyManager
ServerTrustPolicy.swift:73
            objc_setAssociatedObject(self, &AssociatedKeys.ManagerKey, manager, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
{ 0065 static var ManagerKey
ServerTrustPolicy.swift:70
            return objc_getAssociatedObject(self, &AssociatedKeys.ManagerKey) as? ServerTrustPolicyManager
ServerTrustPolicy.swift:73
            objc_setAssociatedObject(self, &AssociatedKeys.ManagerKey, manager, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
= "NSURLSession.ServerTrustPolicyManager" 0066 } 0067 0068 var serverTrustPolicyManager
Manager.swift:155
        session.serverTrustPolicyManager = serverTrustPolicyManager
Manager.swift:293
                    serverTrustPolicy = session.serverTrustPolicyManager?.serverTrustPolicyForHost(host),
Request.swift:275
                    serverTrustPolicy = session.serverTrustPolicyManager?.serverTrustPolicyForHost(host),
: ServerTrustPolicyManager? { 0069 get { 0070 return objc_getAssociatedObject(self, &AssociatedKeys.ManagerKey) as? ServerTrustPolicyManager 0071 } 0072 set (manager) { 0073 objc_setAssociatedObject(self, &AssociatedKeys.ManagerKey, manager, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 0074 } 0075 } 0076 } 0077 0078 // MARK: - ServerTrustPolicy 0079 0080 /** 0081 The `ServerTrustPolicy` evaluates the server trust generally provided by an `NSURLAuthenticationChallenge` when 0082 connecting to a server over a secure HTTPS connection. The policy configuration then evaluates the server trust 0083 with a given set of criteria to determine whether the server trust is valid and the connection should be made. 0084 0085 Using pinned certificates or public keys for evaluation helps prevent man-in-the-middle (MITM) attacks and other 0086 vulnerabilities. Applications dealing with sensitive customer data or financial information are strongly encouraged 0087 to route all communication over an HTTPS connection with pinning enabled. 0088 0089 - PerformDefaultEvaluation: Uses the default server trust evaluation while allowing you to control whether to 0090 validate the host provided by the challenge. Applications are encouraged to always 0091 validate the host in production environments to guarantee the validity of the server's 0092 certificate chain. 0093 0094 - PinCertificates: Uses the pinned certificates to validate the server trust. The server trust is 0095 considered valid if one of the pinned certificates match one of the server certificates. 0096 By validating both the certificate chain and host, certificate pinning provides a very 0097 secure form of server trust validation mitigating most, if not all, MITM attacks. 0098 Applications are encouraged to always validate the host and require a valid certificate 0099 chain in production environments. 0100 0101 - PinPublicKeys: Uses the pinned public keys to validate the server trust. The server trust is considered 0102 valid if one of the pinned public keys match one of the server certificate public keys. 0103 By validating both the certificate chain and host, public key pinning provides a very 0104 secure form of server trust validation mitigating most, if not all, MITM attacks. 0105 Applications are encouraged to always validate the host and require a valid certificate 0106 chain in production environments. 0107 0108 - DisableEvaluation: Disables all evaluation which in turn will always consider any server trust as valid. 0109 0110 - CustomEvaluation: Uses the associated closure to evaluate the validity of the server trust. 0111 */ 0112 public enum ServerTrustPolicy
ServerTrustPolicy.swift:28
    public let policies: [String: ServerTrustPolicy]
ServerTrustPolicy.swift:42
    public init(policies: [String: ServerTrustPolicy]) {
ServerTrustPolicy.swift:56
    public func serverTrustPolicyForHost(host: String) -> ServerTrustPolicy? {
ServerTrustPolicy.swift:218
                outerLoop: for serverPublicKey in ServerTrustPolicy.publicKeysForTrust(serverTrust) as [AnyObject] {
{ 0113 case PerformDefaultEvaluation
ServerTrustPolicy.swift:180
        case let .PerformDefaultEvaluation(validateHost):
(validateHost: Bool) 0114 case PinCertificates
ServerTrustPolicy.swift:185
        case let .PinCertificates(pinnedCertificates, validateCertificateChain, validateHost):
(certificates: [SecCertificate], validateCertificateChain: Bool, validateHost: Bool) 0115 case PinPublicKeys
ServerTrustPolicy.swift:207
        case let .PinPublicKeys(pinnedPublicKeys, validateCertificateChain, validateHost):
(publicKeys: [SecKey], validateCertificateChain: Bool, validateHost: Bool) 0116 case DisableEvaluation
ServerTrustPolicy.swift:227
        case .DisableEvaluation:
0117 case CustomEvaluation
ServerTrustPolicy.swift:229
        case let .CustomEvaluation(closure):
((serverTrust: SecTrust, host: String) -> Bool) 0118 0119 // MARK: - Bundle Location 0120 0121 /** 0122 Returns all certificates within the given bundle with a `.cer` file extension. 0123 0124 - parameter bundle: The bundle to search for all `.cer` files. 0125 0126 - returns: All certificates within the given bundle. 0127 */ 0128 public static func certificatesInBundle
ServerTrustPolicy.swift:157
        for certificate in certificatesInBundle(bundle) {
(bundle: NSBundle = NSBundle.mainBundle()) -> [SecCertificate] { 0129 var certificates: [SecCertificate] = [] 0130 0131 let paths = Set([".cer", ".CER", ".crt", ".CRT", ".der", ".DER"].map { fileExtension in 0132 bundle.pathsForResourcesOfType(fileExtension, inDirectory: nil) 0133 }.flatten()) 0134 0135 for path in paths { 0136 if let 0137 certificateData = NSData(contentsOfFile: path), 0138 certificate = SecCertificateCreateWithData(nil, certificateData) 0139 { 0140 certificates.append(certificate) 0141 } 0142 } 0143 0144 return certificates 0145 } 0146 0147 /** 0148 Returns all public keys within the given bundle with a `.cer` file extension. 0149 0150 - parameter bundle: The bundle to search for all `*.cer` files. 0151 0152 - returns: All public keys within the given bundle. 0153 */ 0154 public static func publicKeysInBundle(bundle: NSBundle = NSBundle.mainBundle()) -> [SecKey] { 0155 var publicKeys: [SecKey] = [] 0156 0157 for certificate in certificatesInBundle(bundle) { 0158 if let publicKey = publicKeyForCertificate(certificate) { 0159 publicKeys.append(publicKey) 0160 } 0161 } 0162 0163 return publicKeys 0164 } 0165 0166 // MARK: - Evaluation 0167 0168 /** 0169 Evaluates whether the server trust is valid for the given host. 0170 0171 - parameter serverTrust: The server trust to evaluate. 0172 - parameter host: The host of the challenge protection space. 0173 0174 - returns: Whether the server trust is valid. 0175 */ 0176 public func evaluateServerTrust
Manager.swift:296
                    if serverTrustPolicy.evaluateServerTrust(serverTrust, isValidForHost: host) {
Request.swift:278
                    if serverTrustPolicy.evaluateServerTrust(serverTrust, isValidForHost: host) {
(serverTrust: SecTrust, isValidForHost host: String) -> Bool { 0177 var serverTrustIsValid = false 0178 0179 switch self { 0180 case let .PerformDefaultEvaluation(validateHost): 0181 let policy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil) 0182 SecTrustSetPolicies(serverTrust, [policy]) 0183 0184 serverTrustIsValid = trustIsValid(serverTrust) 0185 case let .PinCertificates(pinnedCertificates, validateCertificateChain, validateHost): 0186 if validateCertificateChain { 0187 let policy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil) 0188 SecTrustSetPolicies(serverTrust, [policy]) 0189 0190 SecTrustSetAnchorCertificates(serverTrust, pinnedCertificates) 0191 SecTrustSetAnchorCertificatesOnly(serverTrust, true) 0192 0193 serverTrustIsValid = trustIsValid(serverTrust) 0194 } else { 0195 let serverCertificatesDataArray = certificateDataForTrust(serverTrust) 0196 let pinnedCertificatesDataArray = certificateDataForCertificates(pinnedCertificates) 0197 0198 outerLoop: for serverCertificateData in serverCertificatesDataArray { 0199 for pinnedCertificateData in pinnedCertificatesDataArray { 0200 if serverCertificateData.isEqualToData(pinnedCertificateData) { 0201 serverTrustIsValid = true 0202 break outerLoop 0203 } 0204 } 0205 } 0206 } 0207 case let .PinPublicKeys(pinnedPublicKeys, validateCertificateChain, validateHost): 0208 var certificateChainEvaluationPassed = true 0209 0210 if validateCertificateChain { 0211 let policy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil) 0212 SecTrustSetPolicies(serverTrust, [policy]) 0213 0214 certificateChainEvaluationPassed = trustIsValid(serverTrust) 0215 } 0216 0217 if certificateChainEvaluationPassed { 0218 outerLoop: for serverPublicKey in ServerTrustPolicy.publicKeysForTrust(serverTrust) as [AnyObject] { 0219 for pinnedPublicKey in pinnedPublicKeys as [AnyObject] { 0220 if serverPublicKey.isEqual(pinnedPublicKey) { 0221 serverTrustIsValid = true 0222 break outerLoop 0223 } 0224 } 0225 } 0226 } 0227 case .DisableEvaluation: 0228 serverTrustIsValid = true 0229 case let .CustomEvaluation(closure): 0230 serverTrustIsValid = closure(serverTrust: serverTrust, host: host) 0231 } 0232 0233 return serverTrustIsValid 0234 } 0235 0236 // MARK: - Private - Trust Validation 0237 0238 private func trustIsValid
ServerTrustPolicy.swift:184
            serverTrustIsValid = trustIsValid(serverTrust)
ServerTrustPolicy.swift:193
                serverTrustIsValid = trustIsValid(serverTrust)
ServerTrustPolicy.swift:214
                certificateChainEvaluationPassed = trustIsValid(serverTrust)
(trust: SecTrust) -> Bool { 0239 var isValid = false 0240 0241 var result = SecTrustResultType(kSecTrustResultInvalid) 0242 let status = SecTrustEvaluate(trust, &result) 0243 0244 if status == errSecSuccess { 0245 let unspecified = SecTrustResultType(kSecTrustResultUnspecified) 0246 let proceed = SecTrustResultType(kSecTrustResultProceed) 0247 0248 isValid = result == unspecified || result == proceed 0249 } 0250 0251 return isValid 0252 } 0253 0254 // MARK: - Private - Certificate Data 0255 0256 private func certificateDataForTrust
ServerTrustPolicy.swift:195
                let serverCertificatesDataArray = certificateDataForTrust(serverTrust)
(trust: SecTrust) -> [NSData] { 0257 var certificates: [SecCertificate] = [] 0258 0259 for index in 0..<SecTrustGetCertificateCount(trust) { 0260 if let certificate = SecTrustGetCertificateAtIndex(trust, index) { 0261 certificates.append(certificate) 0262 } 0263 } 0264 0265 return certificateDataForCertificates(certificates) 0266 } 0267 0268 private func certificateDataForCertificates
ServerTrustPolicy.swift:196
                let pinnedCertificatesDataArray = certificateDataForCertificates(pinnedCertificates)
ServerTrustPolicy.swift:265
        return certificateDataForCertificates(certificates)
(certificates: [SecCertificate]) -> [NSData] { 0269 return certificates.map { SecCertificateCopyData($0) as NSData } 0270 } 0271 0272 // MARK: - Private - Public Key Extraction 0273 0274 private static func publicKeysForTrust
ServerTrustPolicy.swift:218
                outerLoop: for serverPublicKey in ServerTrustPolicy.publicKeysForTrust(serverTrust) as [AnyObject] {
(trust: SecTrust) -> [SecKey] { 0275 var publicKeys: [SecKey] = [] 0276 0277 for index in 0..<SecTrustGetCertificateCount(trust) { 0278 if let 0279 certificate = SecTrustGetCertificateAtIndex(trust, index), 0280 publicKey = publicKeyForCertificate(certificate) 0281 { 0282 publicKeys.append(publicKey) 0283 } 0284 } 0285 0286 return publicKeys 0287 } 0288 0289 private static func publicKeyForCertificate
ServerTrustPolicy.swift:158
            if let publicKey = publicKeyForCertificate(certificate) {
ServerTrustPolicy.swift:280
                publicKey = publicKeyForCertificate(certificate)
(certificate: SecCertificate) -> SecKey? { 0290 var publicKey: SecKey? 0291 0292 let policy = SecPolicyCreateBasicX509() 0293 var trust: SecTrust? 0294 let trustCreationStatus = SecTrustCreateWithCertificates(certificate, policy, &trust) 0295 0296 if let trust = trust where trustCreationStatus == errSecSuccess { 0297 publicKey = SecTrustCopyPublicKey(trust) 0298 } 0299 0300 return publicKey 0301 } 0302 } 0303