From 872e20a95a551d131a1d23f2030e59ff22da29d6 Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Thu, 18 Oct 2018 12:01:07 +0200 Subject: [PATCH 1/5] Add function to compute MD5 from certificate --- TunnelKit.xcodeproj/project.pbxproj | 4 ++++ TunnelKit/Sources/Core/TLSBox.h | 2 ++ TunnelKit/Sources/Core/TLSBox.m | 19 ++++++++++++++++ TunnelKitTests/EncryptionTests.swift | 8 +++++++ TunnelKitTests/pia-2048.pem | 34 ++++++++++++++++++++++++++++ 5 files changed, 67 insertions(+) create mode 100644 TunnelKitTests/pia-2048.pem diff --git a/TunnelKit.xcodeproj/project.pbxproj b/TunnelKit.xcodeproj/project.pbxproj index e9a80bc..a846cf5 100644 --- a/TunnelKit.xcodeproj/project.pbxproj +++ b/TunnelKit.xcodeproj/project.pbxproj @@ -45,6 +45,7 @@ 0E3E0F212108A8CC00B371C1 /* SessionProxy+PushReply.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3E0F202108A8CC00B371C1 /* SessionProxy+PushReply.swift */; }; 0E3E0F222108A8CC00B371C1 /* SessionProxy+PushReply.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3E0F202108A8CC00B371C1 /* SessionProxy+PushReply.swift */; }; 0E58F1302138AC2F00A49F27 /* DNSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E58F12F2138AC2F00A49F27 /* DNSTests.swift */; }; + 0E749F622178911D00BB2701 /* pia-2048.pem in Resources */ = {isa = PBXBuildFile; fileRef = 0E749F612178911C00BB2701 /* pia-2048.pem */; }; 0E85A25A202CC5AF0059E9F9 /* AppExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E85A259202CC5AE0059E9F9 /* AppExtensionTests.swift */; }; 0E9379C91F819A4300CE91B6 /* TunnelKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E17D7F91F730D9F009EE129 /* TunnelKit.framework */; }; 0EB2B45320F0BB44004233D7 /* EncryptionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB2B45220F0BB44004233D7 /* EncryptionTests.swift */; }; @@ -214,6 +215,7 @@ 0E58F12F2138AC2F00A49F27 /* DNSTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DNSTests.swift; sourceTree = ""; }; 0E6479DD212EAC96008E6888 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 0E6479E0212EACD6008E6888 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 0E749F612178911C00BB2701 /* pia-2048.pem */ = {isa = PBXFileReference; lastKnownFileType = text; path = "pia-2048.pem"; sourceTree = ""; }; 0E85A259202CC5AE0059E9F9 /* AppExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppExtensionTests.swift; sourceTree = ""; }; 0E85A25B202CCA3D0059E9F9 /* TunnelKitHost.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TunnelKitHost.entitlements; sourceTree = ""; }; 0EB2B45220F0BB44004233D7 /* EncryptionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionTests.swift; sourceTree = ""; }; @@ -340,6 +342,7 @@ 0EB2B45620F0BD16004233D7 /* RandomTests.swift */, 0EB2B45C20F0BF41004233D7 /* RawPerformanceTests.swift */, 0EB2B45A20F0BE4C004233D7 /* TestUtils.swift */, + 0E749F612178911C00BB2701 /* pia-2048.pem */, ); path = TunnelKitTests; sourceTree = ""; @@ -719,6 +722,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 0E749F622178911D00BB2701 /* pia-2048.pem in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/TunnelKit/Sources/Core/TLSBox.h b/TunnelKit/Sources/Core/TLSBox.h index 9daf5f1..76e6d54 100644 --- a/TunnelKit/Sources/Core/TLSBox.h +++ b/TunnelKit/Sources/Core/TLSBox.h @@ -51,6 +51,8 @@ extern NSString *const TLSBoxPeerVerificationErrorNotification; // @interface TLSBox : NSObject ++ (NSString *)md5ForCertificatePath:(NSString *)path; + - (instancetype)initWithCAPath:(NSString *)caPath clientCertificatePath:(nullable NSString *)clientCertificatePath clientKeyPath:(nullable NSString *)clientKeyPath; diff --git a/TunnelKit/Sources/Core/TLSBox.m b/TunnelKit/Sources/Core/TLSBox.m index d867a4e..8d2c721 100644 --- a/TunnelKit/Sources/Core/TLSBox.m +++ b/TunnelKit/Sources/Core/TLSBox.m @@ -75,6 +75,25 @@ int TLSBoxVerifyPeer(int ok, X509_STORE_CTX *ctx) { @implementation TLSBox ++ (NSString *)md5ForCertificatePath:(NSString *)path +{ + const EVP_MD *alg = EVP_get_digestbyname("MD5"); + uint8_t md[16]; + unsigned int len; + + FILE *pem = fopen([path cStringUsingEncoding:NSASCIIStringEncoding], "r"); + X509 *cert = PEM_read_X509(pem, NULL, NULL, NULL); + X509_digest(cert, alg, md, &len); + X509_free(cert); + NSCAssert2(len == sizeof(md), @"Unexpected MD5 size (%d != %lu)", len, sizeof(md)); + + NSMutableString *hex = [[NSMutableString alloc] initWithCapacity:2 * sizeof(md)]; + for (int i = 0; i < sizeof(md); ++i) { + [hex appendFormat:@"%02x", md[i]]; + } + return hex; +} + - (instancetype)init { [NSException raise:NSInvalidArgumentException format:@"Use initWithCAPath:clientCertificatePath:clientKeyPath:"]; diff --git a/TunnelKitTests/EncryptionTests.swift b/TunnelKitTests/EncryptionTests.swift index a7b598e..c2f948b 100644 --- a/TunnelKitTests/EncryptionTests.swift +++ b/TunnelKitTests/EncryptionTests.swift @@ -86,6 +86,14 @@ class EncryptionTests: XCTestCase { let decrypted = try! server.decrypter().decryptData(encrypted, extra: extra) XCTAssertEqual(plain, decrypted) } + + func testCertificateMD5() { + let path = Bundle(for: EncryptionTests.self).path(forResource: "pia-2048", ofType: "pem")! + let md5 = TLSBox.md5(forCertificatePath: path) + let exp = "e2fccccaba712ccc68449b1c56427ac1" + print(md5) + XCTAssertEqual(md5, exp) + } private func clientServer(_ c: String?, _ d: String?) -> (CryptoBox, CryptoBox) { let client = CryptoBox(cipherAlgorithm: c, digestAlgorithm: d) diff --git a/TunnelKitTests/pia-2048.pem b/TunnelKitTests/pia-2048.pem new file mode 100644 index 0000000..f1a7d30 --- /dev/null +++ b/TunnelKitTests/pia-2048.pem @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIIFqzCCBJOgAwIBAgIJAKZ7D5Yv87qDMA0GCSqGSIb3DQEBDQUAMIHoMQswCQYD +VQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNV +BAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIElu +dGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3Mx +IDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkB +FiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTAeFw0xNDA0MTcxNzM1 +MThaFw0zNDA0MTIxNzM1MThaMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex +EzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQg +QWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UE +AxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50 +ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVy +bmV0YWNjZXNzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPXD +L1L9tX6DGf36liA7UBTy5I869z0UVo3lImfOs/GSiFKPtInlesP65577nd7UNzzX +lH/P/CnFPdBWlLp5ze3HRBCc/Avgr5CdMRkEsySL5GHBZsx6w2cayQ2EcRhVTwWp +cdldeNO+pPr9rIgPrtXqT4SWViTQRBeGM8CDxAyTopTsobjSiYZCF9Ta1gunl0G/ +8Vfp+SXfYCC+ZzWvP+L1pFhPRqzQQ8k+wMZIovObK1s+nlwPaLyayzw9a8sUnvWB +/5rGPdIYnQWPgoNlLN9HpSmsAcw2z8DXI9pIxbr74cb3/HSfuYGOLkRqrOk6h4RC +OfuWoTrZup1uEOn+fw8CAwEAAaOCAVQwggFQMB0GA1UdDgQWBBQv63nQ/pJAt5tL +y8VJcbHe22ZOsjCCAR8GA1UdIwSCARYwggESgBQv63nQ/pJAt5tLy8VJcbHe22ZO +sqGB7qSB6zCB6DELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRMwEQYDVQQHEwpM +b3NBbmdlbGVzMSAwHgYDVQQKExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4G +A1UECxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAMTF1ByaXZhdGUg +SW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQpExdQcml2YXRlIEludGVybmV0IEFjY2Vz +czEvMC0GCSqGSIb3DQEJARYgc2VjdXJlQHByaXZhdGVpbnRlcm5ldGFjY2Vzcy5j +b22CCQCmew+WL/O6gzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IBAQAn +a5PgrtxfwTumD4+3/SYvwoD66cB8IcK//h1mCzAduU8KgUXocLx7QgJWo9lnZ8xU +ryXvWab2usg4fqk7FPi00bED4f4qVQFVfGfPZIH9QQ7/48bPM9RyfzImZWUCenK3 +7pdw4Bvgoys2rHLHbGen7f28knT2j/cbMxd78tQc20TIObGjo8+ISTRclSTRBtyC +GohseKYpTS9himFERpUgNtefvYHbn70mIOzfOJFTVqfrptf9jXa9N8Mpy3ayfodz +1wiqdteqFXkTYoSDctgKMiZ6GdocK9nMroQipIQtpnwd4yBDWIyC6Bvlkrq5TQUt +YDQ8z9v+DMO6iwyIDRiU +-----END CERTIFICATE----- + From eb8a8b38c23043b7a2e967d7fcd61665c5290181 Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Thu, 18 Oct 2018 11:27:11 +0200 Subject: [PATCH 2/5] Restore PIA HARD_RESET code --- TunnelKit.xcodeproj/project.pbxproj | 6 ++ TunnelKit/Sources/Core/SessionProxy+PIA.swift | 77 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 TunnelKit/Sources/Core/SessionProxy+PIA.swift diff --git a/TunnelKit.xcodeproj/project.pbxproj b/TunnelKit.xcodeproj/project.pbxproj index a846cf5..0b79270 100644 --- a/TunnelKit.xcodeproj/project.pbxproj +++ b/TunnelKit.xcodeproj/project.pbxproj @@ -46,6 +46,8 @@ 0E3E0F222108A8CC00B371C1 /* SessionProxy+PushReply.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3E0F202108A8CC00B371C1 /* SessionProxy+PushReply.swift */; }; 0E58F1302138AC2F00A49F27 /* DNSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E58F12F2138AC2F00A49F27 /* DNSTests.swift */; }; 0E749F622178911D00BB2701 /* pia-2048.pem in Resources */ = {isa = PBXBuildFile; fileRef = 0E749F612178911C00BB2701 /* pia-2048.pem */; }; + 0E749F5F2178885500BB2701 /* SessionProxy+PIA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E749F5E2178885500BB2701 /* SessionProxy+PIA.swift */; }; + 0E749F602178885500BB2701 /* SessionProxy+PIA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E749F5E2178885500BB2701 /* SessionProxy+PIA.swift */; }; 0E85A25A202CC5AF0059E9F9 /* AppExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E85A259202CC5AE0059E9F9 /* AppExtensionTests.swift */; }; 0E9379C91F819A4300CE91B6 /* TunnelKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E17D7F91F730D9F009EE129 /* TunnelKit.framework */; }; 0EB2B45320F0BB44004233D7 /* EncryptionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB2B45220F0BB44004233D7 /* EncryptionTests.swift */; }; @@ -216,6 +218,7 @@ 0E6479DD212EAC96008E6888 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 0E6479E0212EACD6008E6888 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 0E749F612178911C00BB2701 /* pia-2048.pem */ = {isa = PBXFileReference; lastKnownFileType = text; path = "pia-2048.pem"; sourceTree = ""; }; + 0E749F5E2178885500BB2701 /* SessionProxy+PIA.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SessionProxy+PIA.swift"; sourceTree = ""; }; 0E85A259202CC5AE0059E9F9 /* AppExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppExtensionTests.swift; sourceTree = ""; }; 0E85A25B202CCA3D0059E9F9 /* TunnelKitHost.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TunnelKitHost.entitlements; sourceTree = ""; }; 0EB2B45220F0BB44004233D7 /* EncryptionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionTests.swift; sourceTree = ""; }; @@ -475,6 +478,7 @@ 0ED9C8632138139000621BA3 /* SessionProxy+CompressionFraming.swift */, 0E0C2124212ED29D008AB282 /* SessionProxy+Configuration.swift */, 0EFEB42A2006D3C800F81029 /* SessionProxy+EncryptionBridge.swift */, + 0E749F5E2178885500BB2701 /* SessionProxy+PIA.swift */, 0E3E0F202108A8CC00B371C1 /* SessionProxy+PushReply.swift */, 0EFEB42B2006D3C800F81029 /* SessionProxy+SessionKey.swift */, 0EFEB4442006D3C800F81029 /* TLSBox.h */, @@ -873,6 +877,7 @@ 0EC1BBA520D71190007C4C7B /* DNSResolver.swift in Sources */, 0EFEB4AB200760EC00F81029 /* MemoryDestination.swift in Sources */, 0EFEB4AE2007625E00F81029 /* Keychain.swift in Sources */, + 0E749F5F2178885500BB2701 /* SessionProxy+PIA.swift in Sources */, 0EBBF3002085196000E36B40 /* NWTCPConnectionState+Description.swift in Sources */, 0EFEB4622006D3C800F81029 /* SecureRandom.swift in Sources */, 0EFEB45D2006D3C800F81029 /* CryptoBox.m in Sources */, @@ -928,6 +933,7 @@ 0EFEB4B12007627700F81029 /* MemoryDestination.swift in Sources */, 0EC1BBA620D712DE007C4C7B /* DNSResolver.swift in Sources */, 0EFEB4A02006D7F300F81029 /* ReplayProtector.m in Sources */, + 0E749F602178885500BB2701 /* SessionProxy+PIA.swift in Sources */, 0EFEB4992006D7F300F81029 /* SessionProxy.swift in Sources */, 0EBBF3012085196000E36B40 /* NWTCPConnectionState+Description.swift in Sources */, 0EFEB4962006D7F300F81029 /* ProtocolMacros.swift in Sources */, diff --git a/TunnelKit/Sources/Core/SessionProxy+PIA.swift b/TunnelKit/Sources/Core/SessionProxy+PIA.swift new file mode 100644 index 0000000..11c8448 --- /dev/null +++ b/TunnelKit/Sources/Core/SessionProxy+PIA.swift @@ -0,0 +1,77 @@ +// +// SessionProxy+PIA.swift +// TunnelKit +// +// Created by Davide De Rosa on 10/18/18. +// Copyright (c) 2018 Davide De Rosa. All rights reserved. +// +// https://github.com/keeshux +// +// This file is part of TunnelKit. +// +// TunnelKit is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// TunnelKit is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with TunnelKit. If not, see . +// +// This file incorporates work covered by the following copyright and +// permission notice: +// +// Copyright (c) 2018-Present Private Internet Access +// +// 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 + +extension SessionProxy { + struct PIAHardReset { + private static let obfuscationKeyLength = 3 + + private static let magic = "53eo0rk92gxic98p1asgl5auh59r1vp4lmry1e3chzi100qntd" + + private static let encodedFormat = "\(magic)crypto\t%@|%@\tca\t%@" + + private let caMd5Digest: String + + private let cipherName: String + + private let digestName: String + + init(caMd5Digest: String, cipher: Cipher, digest: Digest) { + self.caMd5Digest = caMd5Digest + cipherName = cipher.rawValue.lowercased() + digestName = digest.rawValue.lowercased() + } + + // Ruby: pia_settings + func encodedData() throws -> Data { + guard let plainData = String(format: PIAHardReset.encodedFormat, cipherName, digestName, caMd5Digest).data(using: .ascii) else { + fatalError("Unable to encode string to ASCII") + } + let keyBytes = try SecureRandom.data(length: PIAHardReset.obfuscationKeyLength) + + var encodedData = Data(keyBytes) + for (i, b) in plainData.enumerated() { + let keyChar = keyBytes[i % keyBytes.count] + let xorredB = b ^ keyChar + + encodedData.append(xorredB) + } + return encodedData + } + } +} From 9b785084e248df94244b857e77cfa97645f1de0d Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Thu, 18 Oct 2018 11:36:02 +0200 Subject: [PATCH 3/5] Customize HARD_RESET payload when PIA-patched --- .../TunnelKitProvider+Configuration.swift | 15 +++++++++++++++ .../Sources/AppExtension/TunnelKitProvider.swift | 1 + .../Core/SessionProxy+Configuration.swift | 10 +++++++++- TunnelKit/Sources/Core/SessionProxy.swift | 16 +++++++++++++++- 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/TunnelKit/Sources/AppExtension/TunnelKitProvider+Configuration.swift b/TunnelKit/Sources/AppExtension/TunnelKitProvider+Configuration.swift index 7fc3fee..e8a4d4e 100644 --- a/TunnelKit/Sources/AppExtension/TunnelKitProvider+Configuration.swift +++ b/TunnelKit/Sources/AppExtension/TunnelKitProvider+Configuration.swift @@ -146,6 +146,9 @@ extension TunnelKitProvider { /// The number of seconds after which a renegotiation is started. Set to `nil` to disable renegotiation (default). public var renegotiatesAfterSeconds: Int? + /// Server is patched for the PIA VPN provider. + public var usesPIAPatches: Bool? + // MARK: Debugging /// Enables debugging. If `true`, then `debugLogKey` is a mandatory field. @@ -177,6 +180,7 @@ extension TunnelKitProvider { compressionFraming = .disabled keepAliveSeconds = nil renegotiatesAfterSeconds = nil + usesPIAPatches = false shouldDebug = false debugLogKey = nil debugLogFormat = nil @@ -232,6 +236,7 @@ extension TunnelKitProvider { } keepAliveSeconds = providerConfiguration[S.keepAlive] as? Int renegotiatesAfterSeconds = providerConfiguration[S.renegotiatesAfter] as? Int + usesPIAPatches = providerConfiguration[S.usesPIAPatches] as? Bool ?? false shouldDebug = providerConfiguration[S.debug] as? Bool ?? false if shouldDebug { @@ -268,6 +273,7 @@ extension TunnelKitProvider { compressionFraming: compressionFraming, keepAliveSeconds: keepAliveSeconds, renegotiatesAfterSeconds: renegotiatesAfterSeconds, + usesPIAPatches: usesPIAPatches, shouldDebug: shouldDebug, debugLogKey: shouldDebug ? debugLogKey : nil, debugLogFormat: shouldDebug ? debugLogFormat : nil @@ -304,6 +310,8 @@ extension TunnelKitProvider { static let renegotiatesAfter = "RenegotiatesAfter" + static let usesPIAPatches = "UsesPIAPatches" + static let debug = "Debug" static let debugLogKey = "DebugLogKey" @@ -347,6 +355,9 @@ extension TunnelKitProvider { /// - Seealso: `TunnelKitProvider.ConfigurationBuilder.renegotiatesAfterSeconds` public let renegotiatesAfterSeconds: Int? + /// - Seealso: `TunnelKitProvider.ConfigurationBuilder.usesPIAPatches` + public let usesPIAPatches: Bool? + /// - Seealso: `TunnelKitProvider.ConfigurationBuilder.shouldDebug` public let shouldDebug: Bool @@ -428,6 +439,9 @@ extension TunnelKitProvider { if let renegotiatesAfterSeconds = renegotiatesAfterSeconds { dict[S.renegotiatesAfter] = renegotiatesAfterSeconds } + if let usesPIAPatches = usesPIAPatches { + dict[S.usesPIAPatches] = usesPIAPatches + } if let debugLogKey = debugLogKey { dict[S.debugLogKey] = debugLogKey } @@ -518,6 +532,7 @@ extension TunnelKitProvider.Configuration: Equatable { builder.compressionFraming = compressionFraming builder.keepAliveSeconds = keepAliveSeconds builder.renegotiatesAfterSeconds = renegotiatesAfterSeconds + builder.usesPIAPatches = usesPIAPatches builder.shouldDebug = shouldDebug builder.debugLogKey = debugLogKey builder.debugLogFormat = debugLogFormat diff --git a/TunnelKit/Sources/AppExtension/TunnelKitProvider.swift b/TunnelKit/Sources/AppExtension/TunnelKitProvider.swift index 184ab25..043fe44 100644 --- a/TunnelKit/Sources/AppExtension/TunnelKitProvider.swift +++ b/TunnelKit/Sources/AppExtension/TunnelKitProvider.swift @@ -234,6 +234,7 @@ open class TunnelKitProvider: NEPacketTunnelProvider { if let renegotiatesAfterSeconds = cfg.renegotiatesAfterSeconds { sessionConfiguration.renegotiatesAfter = TimeInterval(renegotiatesAfterSeconds) } + sessionConfiguration.usesPIAPatches = cfg.usesPIAPatches ?? false let proxy: SessionProxy do { diff --git a/TunnelKit/Sources/Core/SessionProxy+Configuration.swift b/TunnelKit/Sources/Core/SessionProxy+Configuration.swift index 7e72abf..be7ea57 100644 --- a/TunnelKit/Sources/Core/SessionProxy+Configuration.swift +++ b/TunnelKit/Sources/Core/SessionProxy+Configuration.swift @@ -162,6 +162,9 @@ extension SessionProxy { /// The number of seconds after which a renegotiation should be initiated. If `nil`, the client will never initiate a renegotiation. public var renegotiatesAfter: TimeInterval? + /// Server is patched for the PIA VPN provider. + public var usesPIAPatches: Bool + /// :nodoc: public init(caPath: String) { credentials = nil @@ -173,6 +176,7 @@ extension SessionProxy { compressionFraming = .disabled keepAliveInterval = nil renegotiatesAfter = nil + usesPIAPatches = false } /** @@ -190,7 +194,8 @@ extension SessionProxy { clientKeyPath: clientKeyPath, compressionFraming: compressionFraming, keepAliveInterval: keepAliveInterval, - renegotiatesAfter: renegotiatesAfter + renegotiatesAfter: renegotiatesAfter, + usesPIAPatches: usesPIAPatches ) } } @@ -224,5 +229,8 @@ extension SessionProxy { /// - Seealso: `SessionProxy.ConfigurationBuilder.renegotiatesAfter` public let renegotiatesAfter: TimeInterval? + + /// - Seealso: `SessionProxy.ConfigurationBuilder.usesPIAPatches` + public let usesPIAPatches: Bool } } diff --git a/TunnelKit/Sources/Core/SessionProxy.swift b/TunnelKit/Sources/Core/SessionProxy.swift index 3c073cf..f384333 100644 --- a/TunnelKit/Sources/Core/SessionProxy.swift +++ b/TunnelKit/Sources/Core/SessionProxy.swift @@ -556,8 +556,22 @@ public class SessionProxy { keys[negotiationKeyIdx] = newKey log.debug("Negotiation key index is \(negotiationKeyIdx)") + let payload = hardResetPayload() ?? Data() negotiationKey.state = .hardReset - enqueueControlPackets(code: .hardResetClientV2, key: UInt8(negotiationKeyIdx), payload: Data()) + enqueueControlPackets(code: .hardResetClientV2, key: UInt8(negotiationKeyIdx), payload: payload) + } + + private func hardResetPayload() -> Data? { + guard !configuration.usesPIAPatches else { + let caMD5 = TLSBox.md5(forCertificatePath: configuration.caPath) + log.debug("CA MD5 is: \(caMD5)") + return try? PIAHardReset( + caMd5Digest: caMD5, + cipher: configuration.cipher, + digest: configuration.digest + ).encodedData() + } + return nil } // Ruby: soft_reset From 961a30cadea5da2773d65e5854761e7a6b44a2bc Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Thu, 18 Oct 2018 12:52:22 +0200 Subject: [PATCH 4/5] Update Demo with PIA patches flag Remember to revert when testing a stock server. --- Demo/BasicTunnel-iOS/ViewController.swift | 3 ++- Demo/Podfile.lock | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Demo/BasicTunnel-iOS/ViewController.swift b/Demo/BasicTunnel-iOS/ViewController.swift index 3af9184..b411947 100644 --- a/Demo/BasicTunnel-iOS/ViewController.swift +++ b/Demo/BasicTunnel-iOS/ViewController.swift @@ -91,11 +91,12 @@ extension ViewController { var builder = TunnelKitProvider.ConfigurationBuilder(ca: ca) let socketType: TunnelKitProvider.SocketType = switchTCP.isOn ? .tcp : .udp builder.endpointProtocols = [TunnelKitProvider.EndpointProtocol(socketType, port)] - builder.cipher = .aes128cbc + builder.cipher = .aes256gcm builder.digest = .sha1 builder.mtu = 1350 builder.compressionFraming = .compLZO builder.renegotiatesAfterSeconds = nil + builder.usesPIAPatches = true builder.shouldDebug = true builder.debugLogKey = "Log" diff --git a/Demo/Podfile.lock b/Demo/Podfile.lock index c02ca3f..29ebc88 100644 --- a/Demo/Podfile.lock +++ b/Demo/Podfile.lock @@ -1,13 +1,13 @@ PODS: - OpenSSL-Apple (1.1.0i-v2) - SwiftyBeaver (1.6.1) - - TunnelKit (1.1.0): - - TunnelKit/AppExtension (= 1.1.0) - - TunnelKit/Core (= 1.1.0) - - TunnelKit/AppExtension (1.1.0): + - TunnelKit (1.1.2): + - TunnelKit/AppExtension (= 1.1.2) + - TunnelKit/Core (= 1.1.2) + - TunnelKit/AppExtension (1.1.2): - SwiftyBeaver - TunnelKit/Core - - TunnelKit/Core (1.1.0): + - TunnelKit/Core (1.1.2): - OpenSSL-Apple (~> 1.1.0h) - SwiftyBeaver @@ -26,7 +26,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: OpenSSL-Apple: a93b8f2eec8783ff40d9a9304de180ab68bb647c SwiftyBeaver: ccfcdf85a04d429f1633f668650b0ce8020bda3a - TunnelKit: 21af89c08aadfa81d25835a1faa46ddf12374772 + TunnelKit: 392e78dd45cded30a6f814200b8334c33901f677 PODFILE CHECKSUM: f66dfaaa92a8d04ab2743f3caeab0ac9f9f25859 From de4fa07b661726bf343e75fd438e4a6c4c018db5 Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Thu, 18 Oct 2018 16:25:42 +0200 Subject: [PATCH 5/5] Update CHANGELOG --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8731138..6c787f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project _will soon adhere_ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Added + +- Restore support for PIA patches. [#32](https://github.com/keeshux/tunnelkit/pull/32) + ## 1.1.1 (2018-10-10) ### Fixed