From 5dc31e7ac373636eb8a028c12f88b35171fe8123 Mon Sep 17 00:00:00 2001 From: Bug Magnet Date: Wed, 31 Jul 2024 14:18:26 +0200 Subject: [PATCH 1/2] Remove ATS entirely --- ios/MullvadVPN/Supporting Files/Info.plist | 33 ---------------------- 1 file changed, 33 deletions(-) diff --git a/ios/MullvadVPN/Supporting Files/Info.plist b/ios/MullvadVPN/Supporting Files/Info.plist index 48854dc4c3f9..14af71cdc743 100644 --- a/ios/MullvadVPN/Supporting Files/Info.plist +++ b/ios/MullvadVPN/Supporting Files/Info.plist @@ -44,39 +44,6 @@ NSAllowsArbitraryLoads - NSExceptionDomains - - 185.217.116.129 - - NSExceptionAllowsInsecureHTTPLoads - - - 127.0.0.1 - - NSExceptionAllowsInsecureHTTPLoads - - - 45.83.223.196 - - NSExceptionAllowsInsecureHTTPLoads - - - - NSPinnedDomains - - am.i.mullvad.net - - NSIncludesSubdomains - - NSPinnedCAIdentities - - - SPKI-SHA256-BASE64 - C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M= - - - - NSUserActivityTypes From 8ff7f7ca9dbbd892f5a3cfc747188c26bfa916bb Mon Sep 17 00:00:00 2001 From: Bug Magnet Date: Wed, 21 Aug 2024 15:26:05 +0200 Subject: [PATCH 2/2] Modify the SSL Pinning logic to support conncheck as well --- .../SSLPinningURLSessionDelegate.swift | 28 +++++++++++++++---- ios/MullvadVPN/SceneDelegate.swift | 2 +- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/ios/MullvadREST/ApiHandlers/SSLPinningURLSessionDelegate.swift b/ios/MullvadREST/ApiHandlers/SSLPinningURLSessionDelegate.swift index 6ab457fd4902..2d0d1ca40625 100644 --- a/ios/MullvadREST/ApiHandlers/SSLPinningURLSessionDelegate.swift +++ b/ios/MullvadREST/ApiHandlers/SSLPinningURLSessionDelegate.swift @@ -8,6 +8,7 @@ import Foundation import MullvadLogging +import Network import Security final class SSLPinningURLSessionDelegate: NSObject, URLSessionDelegate { @@ -29,17 +30,32 @@ final class SSLPinningURLSessionDelegate: NSObject, URLSessionDelegate { completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void ) { if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust, - let serverTrust = challenge.protectionSpace.serverTrust, - verifyServerTrust(serverTrust) { - completionHandler(.useCredential, URLCredential(trust: serverTrust)) - } else { - completionHandler(.rejectProtectionSpace, nil) + let serverTrust = challenge.protectionSpace.serverTrust { + /// If a request is going through a local shadowsocks proxy, the host would be a localhost address,` + /// which would not appear in the list of valid host names in the root certificate. + /// The same goes for direct connections to the API, the host would be the IP address of the endpoint. + /// Certificates, cannot be signed for IP addresses, in such case, specify that the host name is `defaultAPIHostname` + var hostName = challenge.protectionSpace.host + let overridenHostnames = [ + "\(IPv4Address.loopback)", + "\(IPv6Address.loopback)", + "\(REST.defaultAPIEndpoint.ip)", + ] + if overridenHostnames.contains(hostName) { + hostName = sslHostname + } + + if verifyServerTrust(serverTrust, for: hostName) { + completionHandler(.useCredential, URLCredential(trust: serverTrust)) + return + } } + completionHandler(.rejectProtectionSpace, nil) } // MARK: - Private - private func verifyServerTrust(_ serverTrust: SecTrust) -> Bool { + private func verifyServerTrust(_ serverTrust: SecTrust, for sslHostname: String) -> Bool { var secResult: OSStatus // Set SSL policy diff --git a/ios/MullvadVPN/SceneDelegate.swift b/ios/MullvadVPN/SceneDelegate.swift index d70b631b3737..618555f5fe7a 100644 --- a/ios/MullvadVPN/SceneDelegate.swift +++ b/ios/MullvadVPN/SceneDelegate.swift @@ -74,7 +74,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, SettingsMigrationUIHand accountsProxy: appDelegate.accountsProxy, outgoingConnectionService: OutgoingConnectionService( outgoingConnectionProxy: OutgoingConnectionProxy( - urlSession: URLSession(configuration: .ephemeral), + urlSession: REST.makeURLSession(), hostname: ApplicationConfiguration.hostName ) ),