Merge pull request #28 from keeshux/review-optional-configuration
Review optional configuration
This commit is contained in:
commit
f5161a0c39
|
@ -47,7 +47,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
var window: UIWindow?
|
||||
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
let logDestination = ConsoleDestination()
|
||||
logDestination.minLevel = .debug
|
||||
logDestination.format = "$DHH:mm:ss$d $L $N.$F:$l - $M"
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
</array>
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$(AppIdentifierPrefix)group.com.privateinternetaccess.ios.demo.BasicTunnel</string>
|
||||
<string>$(AppIdentifierPrefix)group.com.algoritmico.ios.demo.BasicTunnel</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -3,13 +3,78 @@
|
|||
// BasicTunnel-iOS
|
||||
//
|
||||
// Created by Davide De Rosa on 2/11/17.
|
||||
// Copyright © 2018 Davide De Rosa. All rights reserved.
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// 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 UIKit
|
||||
import NetworkExtension
|
||||
import TunnelKit
|
||||
|
||||
private let ca = CryptoContainer(pem: """
|
||||
-----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-----
|
||||
""")
|
||||
|
||||
extension ViewController {
|
||||
private static let appGroup = "group.com.algoritmico.ios.demo.BasicTunnel"
|
||||
|
||||
|
@ -21,16 +86,9 @@ extension ViewController {
|
|||
|
||||
let hostname = ((domain == "") ? server : [server, domain].joined(separator: "."))
|
||||
let port = UInt16(textPort.text!)!
|
||||
let username = textUsername.text!
|
||||
let password = textPassword.text!
|
||||
let credentials = SessionProxy.Credentials(textUsername.text!, textPassword.text!)
|
||||
|
||||
let endpoint = TunnelKitProvider.AuthenticatedEndpoint(
|
||||
hostname: hostname,
|
||||
username: username,
|
||||
password: password
|
||||
)
|
||||
|
||||
var builder = TunnelKitProvider.ConfigurationBuilder()
|
||||
var builder = TunnelKitProvider.ConfigurationBuilder(ca: ca)
|
||||
let socketType: TunnelKitProvider.SocketType = switchTCP.isOn ? .tcp : .udp
|
||||
builder.endpointProtocols = [TunnelKitProvider.EndpointProtocol(socketType, port)]
|
||||
builder.cipher = .aes128cbc
|
||||
|
@ -45,7 +103,8 @@ extension ViewController {
|
|||
return try! configuration.generatedTunnelProtocol(
|
||||
withBundleIdentifier: ViewController.bundleIdentifier,
|
||||
appGroup: ViewController.appGroup,
|
||||
endpoint: endpoint
|
||||
hostname: hostname,
|
||||
credentials: credentials
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,13 +3,78 @@
|
|||
// BasicTunnel-macOS
|
||||
//
|
||||
// Created by Davide De Rosa on 10/15/17.
|
||||
// Copyright © 2018 Davide De Rosa. All rights reserved.
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// 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 Cocoa
|
||||
import NetworkExtension
|
||||
import TunnelKit
|
||||
|
||||
private let ca = CryptoContainer(pem: """
|
||||
-----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-----
|
||||
""")
|
||||
|
||||
extension ViewController {
|
||||
private static let appGroup = "group.com.algoritmico.macos.demo.BasicTunnel"
|
||||
|
||||
|
@ -21,16 +86,9 @@ extension ViewController {
|
|||
|
||||
let hostname = ((domain == "") ? server : [server, domain].joined(separator: "."))
|
||||
let port = UInt16(textPort.stringValue)!
|
||||
let username = textUsername.stringValue
|
||||
let password = textPassword.stringValue
|
||||
let credentials = SessionProxy.Credentials(textUsername.stringValue, textPassword.stringValue)
|
||||
|
||||
let endpoint = TunnelKitProvider.AuthenticatedEndpoint(
|
||||
hostname: hostname,
|
||||
username: username,
|
||||
password: password
|
||||
)
|
||||
|
||||
var builder = TunnelKitProvider.ConfigurationBuilder()
|
||||
var builder = TunnelKitProvider.ConfigurationBuilder(ca: ca)
|
||||
// let socketType: TunnelKitProvider.SocketType = isTCP ? .tcp : .udp
|
||||
let socketType: TunnelKitProvider.SocketType = .udp
|
||||
builder.endpointProtocols = [TunnelKitProvider.EndpointProtocol(socketType, port)]
|
||||
|
@ -46,7 +104,8 @@ extension ViewController {
|
|||
return try! configuration.generatedTunnelProtocol(
|
||||
withBundleIdentifier: ViewController.bundleIdentifier,
|
||||
appGroup: ViewController.appGroup,
|
||||
endpoint: endpoint
|
||||
hostname: hostname,
|
||||
credentials: credentials
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
</array>
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$(AppIdentifierPrefix)group.com.privateinternetaccess.ios.demo.BasicTunnel</string>
|
||||
<string>$(AppIdentifierPrefix)group.com.algoritmico.ios.demo.BasicTunnel</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -289,7 +289,7 @@
|
|||
0EB39FE31F7424F80023AFFC /* Frameworks */,
|
||||
0EB39FE41F7424F80023AFFC /* Resources */,
|
||||
0EB3A0091F7425140023AFFC /* Embed App Extensions */,
|
||||
A3C198CD449DD5434CB4A22E /* [CP] Embed Pods Frameworks */,
|
||||
B144DFB36177A29B7E1B0DA4 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
@ -365,11 +365,12 @@
|
|||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0900;
|
||||
LastUpgradeCheck = 0900;
|
||||
LastUpgradeCheck = 1000;
|
||||
ORGANIZATIONNAME = "Davide De Rosa";
|
||||
TargetAttributes = {
|
||||
0EB39FE51F7424F80023AFFC = {
|
||||
CreatedOnToolsVersion = 9.0;
|
||||
LastSwiftMigration = 1000;
|
||||
ProvisioningStyle = Automatic;
|
||||
SystemCapabilities = {
|
||||
com.apple.ApplicationGroups.iOS = {
|
||||
|
@ -382,6 +383,7 @@
|
|||
};
|
||||
0EB39FFB1F7425140023AFFC = {
|
||||
CreatedOnToolsVersion = 9.0;
|
||||
LastSwiftMigration = 1000;
|
||||
ProvisioningStyle = Automatic;
|
||||
SystemCapabilities = {
|
||||
com.apple.ApplicationGroups.iOS = {
|
||||
|
@ -532,32 +534,6 @@
|
|||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
A3C198CD449DD5434CB4A22E /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${SRCROOT}/Pods/Target Support Files/Pods-iOS-BasicTunnel-iOS/Pods-iOS-BasicTunnel-iOS-frameworks.sh",
|
||||
"${PODS_ROOT}/OpenSSL-Apple/frameworks/iPhone/openssl.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/SwiftyBeaver-iOS/SwiftyBeaver.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/TunnelKit-iOS/TunnelKit.framework",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyBeaver.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/TunnelKit.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-iOS-BasicTunnel-iOS/Pods-iOS-BasicTunnel-iOS-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
AC2C3BCB219270755C04C726 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -566,7 +542,7 @@
|
|||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${SRCROOT}/Pods/Target Support Files/Pods-macOS-BasicTunnel-macOS/Pods-macOS-BasicTunnel-macOS-frameworks.sh",
|
||||
"${PODS_ROOT}/Target Support Files/Pods-macOS-BasicTunnel-macOS/Pods-macOS-BasicTunnel-macOS-frameworks.sh",
|
||||
"${PODS_ROOT}/OpenSSL-Apple/frameworks/MacOSX/openssl.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/SwiftyBeaver-macOS/SwiftyBeaver.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/TunnelKit-macOS/TunnelKit.framework",
|
||||
|
@ -581,7 +557,33 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-macOS-BasicTunnel-macOS/Pods-macOS-BasicTunnel-macOS-frameworks.sh\"\n";
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-macOS-BasicTunnel-macOS/Pods-macOS-BasicTunnel-macOS-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
B144DFB36177A29B7E1B0DA4 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-iOS-BasicTunnel-iOS/Pods-iOS-BasicTunnel-iOS-frameworks.sh",
|
||||
"${PODS_ROOT}/OpenSSL-Apple/frameworks/iPhone/openssl.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/SwiftyBeaver-iOS/SwiftyBeaver.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/TunnelKit-iOS/TunnelKit.framework",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyBeaver.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/TunnelKit.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-iOS-BasicTunnel-iOS/Pods-iOS-BasicTunnel-iOS-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
C772E0EE406756CD998F1DFD /* [CP] Check Pods Manifest.lock */ = {
|
||||
|
@ -722,6 +724,7 @@
|
|||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
|
@ -729,6 +732,7 @@
|
|||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
|
@ -756,14 +760,14 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 4.2;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
@ -781,6 +785,7 @@
|
|||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
|
@ -788,6 +793,7 @@
|
|||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
|
@ -809,12 +815,12 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 4.2;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
|
|
|
@ -2,7 +2,7 @@ source 'https://github.com/CocoaPods/Specs.git'
|
|||
use_frameworks!
|
||||
|
||||
abstract_target 'iOS' do
|
||||
platform :ios, '9.0'
|
||||
platform :ios, '11.0'
|
||||
|
||||
target 'BasicTunnelExtension-iOS' do
|
||||
pod 'TunnelKit', :path => '..'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
PODS:
|
||||
- OpenSSL-Apple (1.1.0h)
|
||||
- SwiftyBeaver (1.6.0)
|
||||
- OpenSSL-Apple (1.1.0i-v2)
|
||||
- SwiftyBeaver (1.6.1)
|
||||
- TunnelKit (1.1.0):
|
||||
- TunnelKit/AppExtension (= 1.1.0)
|
||||
- TunnelKit/Core (= 1.1.0)
|
||||
|
@ -24,10 +24,10 @@ EXTERNAL SOURCES:
|
|||
:path: ".."
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
OpenSSL-Apple: cd153d705ef350eb834ae7ff5f21f792b51ed208
|
||||
SwiftyBeaver: e45759613e50b522b0e6f53b1f0f14389b45ca34
|
||||
TunnelKit: 4c10192ab76e9b03bf5bde5b70f38e38ae6d4568
|
||||
OpenSSL-Apple: a93b8f2eec8783ff40d9a9304de180ab68bb647c
|
||||
SwiftyBeaver: ccfcdf85a04d429f1633f668650b0ce8020bda3a
|
||||
TunnelKit: 21af89c08aadfa81d25835a1faa46ddf12374772
|
||||
|
||||
PODFILE CHECKSUM: dbd445ce3249028c60f04276181924bb9bfc726d
|
||||
PODFILE CHECKSUM: f66dfaaa92a8d04ab2743f3caeab0ac9f9f25859
|
||||
|
||||
COCOAPODS: 1.5.3
|
||||
COCOAPODS: 1.6.0.beta.1
|
||||
|
|
|
@ -6,10 +6,15 @@ DEPENDENCIES:
|
|||
- OpenSSL-Apple (~> 1.1.0i)
|
||||
- SwiftyBeaver
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/cocoapods/specs.git:
|
||||
- OpenSSL-Apple
|
||||
- SwiftyBeaver
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
OpenSSL-Apple: a93b8f2eec8783ff40d9a9304de180ab68bb647c
|
||||
SwiftyBeaver: ccfcdf85a04d429f1633f668650b0ce8020bda3a
|
||||
|
||||
PODFILE CHECKSUM: 7cd71c5bc177daedf9933b9428b39c0c9ffae5a6
|
||||
|
||||
COCOAPODS: 1.4.0
|
||||
COCOAPODS: 1.6.0.beta.1
|
||||
|
|
|
@ -127,7 +127,7 @@ For more details please see [CONTRIBUTING][contrib-readme].
|
|||
|
||||
### Part I
|
||||
|
||||
Copyright 2018-present Davide De Rosa
|
||||
Copyright 2018 Davide De Rosa
|
||||
|
||||
This project is licensed under the [GPLv3 license][license-gpl3], which can be found [here][license-content].
|
||||
|
||||
|
|
|
@ -604,7 +604,6 @@
|
|||
0E1108A61F77B9F900A92462 /* Frameworks */,
|
||||
0E1108A71F77B9F900A92462 /* Resources */,
|
||||
B90665BB6148F76EE6C7B876 /* [CP] Embed Pods Frameworks */,
|
||||
CB8BC028A305D776BF99051F /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
@ -625,7 +624,6 @@
|
|||
0E17D7F51F730D9F009EE129 /* Frameworks */,
|
||||
0E17D7F61F730D9F009EE129 /* Headers */,
|
||||
0E17D7F71F730D9F009EE129 /* Resources */,
|
||||
D908F7F68DFAC49339D3642D /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
@ -645,7 +643,6 @@
|
|||
0E3251C11F95770D00C108D9 /* Frameworks */,
|
||||
0E3251C21F95770D00C108D9 /* Headers */,
|
||||
0E3251C31F95770D00C108D9 /* Resources */,
|
||||
4D0B460E051C7982B3C6766D /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
@ -770,25 +767,6 @@
|
|||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
4D0B460E051C7982B3C6766D /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-TunnelKit-TunnelKit-macOS/Pods-TunnelKit-TunnelKit-macOS-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
94AA64A70C6BF0AD8E5BA279 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -831,7 +809,7 @@
|
|||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${SRCROOT}/Pods/Target Support Files/Pods-TunnelKit-TunnelKitHost/Pods-TunnelKit-TunnelKitHost-frameworks.sh",
|
||||
"${PODS_ROOT}/Target Support Files/Pods-TunnelKit-TunnelKitHost/Pods-TunnelKit-TunnelKitHost-frameworks.sh",
|
||||
"${PODS_ROOT}/OpenSSL-Apple/frameworks/iPhone/openssl.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/SwiftyBeaver-iOS/SwiftyBeaver.framework",
|
||||
);
|
||||
|
@ -842,45 +820,7 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-TunnelKit-TunnelKitHost/Pods-TunnelKit-TunnelKitHost-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
CB8BC028A305D776BF99051F /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-TunnelKit-TunnelKitHost/Pods-TunnelKit-TunnelKitHost-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
D908F7F68DFAC49339D3642D /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-TunnelKit-TunnelKit-iOS/Pods-TunnelKit-TunnelKit-iOS-resources.sh\"\n";
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-TunnelKit-TunnelKitHost/Pods-TunnelKit-TunnelKitHost-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
|
|
@ -105,45 +105,6 @@ extension TunnelKitProvider {
|
|||
}
|
||||
}
|
||||
|
||||
/// Encapsulates an endpoint along with the authentication credentials.
|
||||
public struct AuthenticatedEndpoint {
|
||||
|
||||
/// The remote hostname or IP address.
|
||||
public let hostname: String
|
||||
|
||||
/// The username.
|
||||
public let username: String
|
||||
|
||||
/// The password.
|
||||
public let password: String
|
||||
|
||||
/// :nodoc:
|
||||
public init(hostname: String, username: String, password: String) {
|
||||
self.hostname = hostname
|
||||
self.username = username
|
||||
self.password = password
|
||||
}
|
||||
|
||||
init(protocolConfiguration: NEVPNProtocol) throws {
|
||||
guard let hostname = protocolConfiguration.serverAddress else {
|
||||
throw ProviderError.configuration(field: "protocolConfiguration.serverAddress")
|
||||
}
|
||||
guard let username = protocolConfiguration.username else {
|
||||
throw ProviderError.credentials(field: "protocolConfiguration.username")
|
||||
}
|
||||
guard let passwordReference = protocolConfiguration.passwordReference else {
|
||||
throw ProviderError.credentials(field: "protocolConfiguration.passwordReference")
|
||||
}
|
||||
guard let password = try? Keychain.password(for: username, reference: passwordReference) else {
|
||||
throw ProviderError.credentials(field: "protocolConfiguration.passwordReference (keychain)")
|
||||
}
|
||||
|
||||
self.hostname = hostname
|
||||
self.username = username
|
||||
self.password = password
|
||||
}
|
||||
}
|
||||
|
||||
/// The way to create a `TunnelKitProvider.Configuration` object for the tunnel profile.
|
||||
public struct ConfigurationBuilder {
|
||||
|
||||
|
@ -164,8 +125,8 @@ extension TunnelKitProvider {
|
|||
/// The message digest algorithm.
|
||||
public var digest: SessionProxy.Digest
|
||||
|
||||
/// The optional CA certificate to validate server against. Set to `nil` to disable CA validation (default).
|
||||
public var ca: CryptoContainer?
|
||||
/// The CA certificate to validate server against.
|
||||
public let ca: CryptoContainer
|
||||
|
||||
/// The optional client certificate to authenticate with. Set to `nil` to disable client authentication (default).
|
||||
public var clientCertificate: CryptoContainer?
|
||||
|
@ -200,14 +161,16 @@ extension TunnelKitProvider {
|
|||
|
||||
/**
|
||||
Default initializer.
|
||||
|
||||
- Parameter ca: The CA certificate.
|
||||
*/
|
||||
public init() {
|
||||
public init(ca: CryptoContainer) {
|
||||
prefersResolvedAddresses = false
|
||||
resolvedAddresses = nil
|
||||
endpointProtocols = [EndpointProtocol(.udp, 1194)]
|
||||
cipher = .aes128cbc
|
||||
digest = .sha1
|
||||
ca = nil
|
||||
self.ca = ca
|
||||
clientCertificate = nil
|
||||
clientKey = nil
|
||||
mtu = 1500
|
||||
|
@ -229,20 +192,19 @@ extension TunnelKitProvider {
|
|||
throw ProviderError.configuration(field: "protocolConfiguration.providerConfiguration[\(S.digestAlgorithm)]")
|
||||
}
|
||||
|
||||
let ca: CryptoContainer?
|
||||
let ca: CryptoContainer
|
||||
let clientCertificate: CryptoContainer?
|
||||
let clientKey: CryptoContainer?
|
||||
if let pem = providerConfiguration[S.ca] as? String {
|
||||
ca = CryptoContainer(pem: pem)
|
||||
} else {
|
||||
ca = nil
|
||||
guard let caPEM = providerConfiguration[S.ca] as? String else {
|
||||
throw ProviderError.configuration(field: "protocolConfiguration.providerConfiguration[\(S.ca)]")
|
||||
}
|
||||
if let pem = providerConfiguration[S.clientCertificate] as? String {
|
||||
ca = CryptoContainer(pem: caPEM)
|
||||
if let clientPEM = providerConfiguration[S.clientCertificate] as? String {
|
||||
guard let keyPEM = providerConfiguration[S.clientKey] as? String else {
|
||||
throw ProviderError.configuration(field: "protocolConfiguration.providerConfiguration[\(S.clientKey)]")
|
||||
}
|
||||
|
||||
clientCertificate = CryptoContainer(pem: pem)
|
||||
clientCertificate = CryptoContainer(pem: clientPEM)
|
||||
clientKey = CryptoContainer(pem: keyPEM)
|
||||
} else {
|
||||
clientCertificate = nil
|
||||
|
@ -365,7 +327,7 @@ extension TunnelKitProvider {
|
|||
public let digest: SessionProxy.Digest
|
||||
|
||||
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.ca`
|
||||
public let ca: CryptoContainer?
|
||||
public let ca: CryptoContainer
|
||||
|
||||
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.clientCertificate`
|
||||
public let clientCertificate: CryptoContainer?
|
||||
|
@ -446,12 +408,10 @@ extension TunnelKitProvider {
|
|||
S.endpointProtocols: endpointProtocols.map { $0.serialized() },
|
||||
S.cipherAlgorithm: cipher.rawValue,
|
||||
S.digestAlgorithm: digest.rawValue,
|
||||
S.ca: ca.pem,
|
||||
S.mtu: mtu,
|
||||
S.debug: shouldDebug
|
||||
]
|
||||
if let ca = ca {
|
||||
dict[S.ca] = ca.pem
|
||||
}
|
||||
if let clientCertificate = clientCertificate {
|
||||
dict[S.clientCertificate] = clientCertificate.pem
|
||||
}
|
||||
|
@ -482,24 +442,26 @@ extension TunnelKitProvider {
|
|||
|
||||
- Parameter bundleIdentifier: The provider bundle identifier required to locate the tunnel extension.
|
||||
- Parameter appGroup: The name of the app group in which the tunnel extension lives in.
|
||||
- Parameter endpoint: The `TunnelKitProvider.AuthenticatedEndpoint` the tunnel will connect to.
|
||||
- Parameter hostname: The hostname the tunnel will connect to.
|
||||
- Parameter credentials: The optional credentials to authenticate with.
|
||||
- Returns: The generated `NETunnelProviderProtocol` object.
|
||||
- Throws: `ProviderError.configuration` if unable to store the `endpoint.password` to the `appGroup` keychain.
|
||||
- Throws: `ProviderError.credentials` if unable to store `credentials.password` to the `appGroup` keychain.
|
||||
*/
|
||||
public func generatedTunnelProtocol(withBundleIdentifier bundleIdentifier: String, appGroup: String, endpoint: AuthenticatedEndpoint) throws -> NETunnelProviderProtocol {
|
||||
public func generatedTunnelProtocol(withBundleIdentifier bundleIdentifier: String, appGroup: String, hostname: String, credentials: SessionProxy.Credentials? = nil) throws -> NETunnelProviderProtocol {
|
||||
let protocolConfiguration = NETunnelProviderProtocol()
|
||||
|
||||
let keychain = Keychain(group: appGroup)
|
||||
do {
|
||||
try keychain.set(password: endpoint.password, for: endpoint.username, label: Bundle.main.bundleIdentifier)
|
||||
} catch _ {
|
||||
throw ProviderError.credentials(field: "keychain.set()")
|
||||
}
|
||||
|
||||
protocolConfiguration.providerBundleIdentifier = bundleIdentifier
|
||||
protocolConfiguration.serverAddress = endpoint.hostname
|
||||
protocolConfiguration.username = endpoint.username
|
||||
protocolConfiguration.passwordReference = try? keychain.passwordReference(for: endpoint.username)
|
||||
protocolConfiguration.serverAddress = hostname
|
||||
if let username = credentials?.username, let password = credentials?.password {
|
||||
let keychain = Keychain(group: appGroup)
|
||||
do {
|
||||
try keychain.set(password: password, for: username, label: Bundle.main.bundleIdentifier)
|
||||
} catch _ {
|
||||
throw ProviderError.credentials(field: "keychain.set()")
|
||||
}
|
||||
protocolConfiguration.username = username
|
||||
protocolConfiguration.passwordReference = try? keychain.passwordReference(for: username)
|
||||
}
|
||||
protocolConfiguration.providerConfiguration = generatedProviderConfiguration(appGroup: appGroup)
|
||||
|
||||
return protocolConfiguration
|
||||
|
@ -514,11 +476,6 @@ extension TunnelKitProvider {
|
|||
log.info("\tProtocols: \(endpointProtocols)")
|
||||
log.info("\tCipher: \(cipher)")
|
||||
log.info("\tDigest: \(digest)")
|
||||
if let _ = ca {
|
||||
log.info("\tCA verification: enabled")
|
||||
} else {
|
||||
log.info("\tCA verification: disabled")
|
||||
}
|
||||
if let _ = clientCertificate {
|
||||
log.info("\tClient verification: enabled")
|
||||
} else {
|
||||
|
@ -551,11 +508,10 @@ extension TunnelKitProvider.Configuration: Equatable {
|
|||
- Returns: An editable `TunnelKitProvider.ConfigurationBuilder` initialized with this configuration.
|
||||
*/
|
||||
public func builder() -> TunnelKitProvider.ConfigurationBuilder {
|
||||
var builder = TunnelKitProvider.ConfigurationBuilder()
|
||||
var builder = TunnelKitProvider.ConfigurationBuilder(ca: ca)
|
||||
builder.endpointProtocols = endpointProtocols
|
||||
builder.cipher = cipher
|
||||
builder.digest = digest
|
||||
builder.ca = ca
|
||||
builder.clientCertificate = clientCertificate
|
||||
builder.clientKey = clientKey
|
||||
builder.mtu = mtu
|
||||
|
|
|
@ -116,24 +116,26 @@ open class TunnelKitProvider: NEPacketTunnelProvider {
|
|||
|
||||
/// :nodoc:
|
||||
open override func startTunnel(options: [String : NSObject]? = nil, completionHandler: @escaping (Error?) -> Void) {
|
||||
let endpoint: AuthenticatedEndpoint
|
||||
|
||||
// required configuration
|
||||
let hostname: String
|
||||
do {
|
||||
guard let tunnelProtocol = protocolConfiguration as? NETunnelProviderProtocol else {
|
||||
throw ProviderError.configuration(field: "protocolConfiguration")
|
||||
}
|
||||
guard let serverAddress = tunnelProtocol.serverAddress else {
|
||||
throw ProviderError.configuration(field: "protocolConfiguration.serverAddress")
|
||||
}
|
||||
guard let providerConfiguration = tunnelProtocol.providerConfiguration else {
|
||||
throw ProviderError.configuration(field: "protocolConfiguration.providerConfiguration")
|
||||
}
|
||||
try endpoint = AuthenticatedEndpoint(protocolConfiguration: tunnelProtocol)
|
||||
hostname = serverAddress
|
||||
try appGroup = Configuration.appGroup(from: providerConfiguration)
|
||||
try cfg = Configuration.parsed(from: providerConfiguration)
|
||||
} catch let e {
|
||||
var message: String?
|
||||
if let te = e as? ProviderError {
|
||||
switch te {
|
||||
case .credentials(let field):
|
||||
message = "Tunnel credentials unavailable: \(field)"
|
||||
|
||||
case .configuration(let field):
|
||||
message = "Tunnel configuration incomplete: \(field)"
|
||||
|
||||
|
@ -146,7 +148,16 @@ open class TunnelKitProvider: NEPacketTunnelProvider {
|
|||
return
|
||||
}
|
||||
|
||||
strategy = ConnectionStrategy(hostname: endpoint.hostname, configuration: cfg)
|
||||
// optional credentials
|
||||
let credentials: SessionProxy.Credentials?
|
||||
if let username = protocolConfiguration.username, let passwordReference = protocolConfiguration.passwordReference,
|
||||
let password = try? Keychain.password(for: username, reference: passwordReference) {
|
||||
credentials = SessionProxy.Credentials(username, password)
|
||||
} else {
|
||||
credentials = nil
|
||||
}
|
||||
|
||||
strategy = ConnectionStrategy(hostname: hostname, configuration: cfg)
|
||||
|
||||
if let defaults = defaults, var existingLog = cfg.existingLog(in: defaults) {
|
||||
if let i = existingLog.index(of: logSeparator) {
|
||||
|
@ -171,20 +182,16 @@ open class TunnelKitProvider: NEPacketTunnelProvider {
|
|||
return
|
||||
}
|
||||
|
||||
let caPath: String?
|
||||
let caPath: String
|
||||
let clientCertificatePath: String?
|
||||
let clientKeyPath: String?
|
||||
if let ca = cfg.ca {
|
||||
do {
|
||||
let url = temporaryURL(forKey: Configuration.Keys.ca)
|
||||
try ca.write(to: url)
|
||||
caPath = url.path
|
||||
} catch {
|
||||
completionHandler(ProviderError.certificateSerialization)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
caPath = nil
|
||||
do {
|
||||
let url = temporaryURL(forKey: Configuration.Keys.ca)
|
||||
try cfg.ca.write(to: url)
|
||||
caPath = url.path
|
||||
} catch {
|
||||
completionHandler(ProviderError.certificateSerialization)
|
||||
return
|
||||
}
|
||||
if let clientCertificate = cfg.clientCertificate {
|
||||
do {
|
||||
|
@ -214,10 +221,10 @@ open class TunnelKitProvider: NEPacketTunnelProvider {
|
|||
cfg.print(appVersion: appVersion)
|
||||
|
||||
// log.info("Temporary CA is stored to: \(caPath)")
|
||||
var sessionConfiguration = SessionProxy.ConfigurationBuilder(username: endpoint.username, password: endpoint.password)
|
||||
var sessionConfiguration = SessionProxy.ConfigurationBuilder(caPath: caPath)
|
||||
sessionConfiguration.credentials = credentials
|
||||
sessionConfiguration.cipher = cfg.cipher
|
||||
sessionConfiguration.digest = cfg.digest
|
||||
sessionConfiguration.caPath = caPath
|
||||
sessionConfiguration.clientCertificatePath = clientCertificatePath
|
||||
sessionConfiguration.clientKeyPath = clientKeyPath
|
||||
sessionConfiguration.compressionFraming = cfg.compressionFraming
|
||||
|
|
|
@ -62,18 +62,23 @@ extension SessionProxy {
|
|||
|
||||
private(set) var serverRandom2: ZeroingData?
|
||||
|
||||
let username: ZeroingData
|
||||
let username: ZeroingData?
|
||||
|
||||
let password: ZeroingData
|
||||
let password: ZeroingData?
|
||||
|
||||
init(_ username: String, _ password: String) throws {
|
||||
init(_ username: String?, _ password: String?) throws {
|
||||
preMaster = try SecureRandom.safeData(length: CoreConfiguration.preMasterLength)
|
||||
random1 = try SecureRandom.safeData(length: CoreConfiguration.randomLength)
|
||||
random2 = try SecureRandom.safeData(length: CoreConfiguration.randomLength)
|
||||
|
||||
// XXX: not 100% secure, can't erase input username/password
|
||||
self.username = Z(username, nullTerminated: true)
|
||||
self.password = Z(password, nullTerminated: true)
|
||||
if let username = username, let password = password {
|
||||
self.username = Z(username, nullTerminated: true)
|
||||
self.password = Z(password, nullTerminated: true)
|
||||
} else {
|
||||
self.username = nil
|
||||
self.password = nil
|
||||
}
|
||||
|
||||
controlBuffer = Z()
|
||||
}
|
||||
|
@ -93,8 +98,13 @@ extension SessionProxy {
|
|||
raw.appendSized(Z(UInt8(0)))
|
||||
|
||||
// credentials
|
||||
raw.appendSized(username)
|
||||
raw.appendSized(password)
|
||||
if let username = username, let password = password {
|
||||
raw.appendSized(username)
|
||||
raw.appendSized(password)
|
||||
} else {
|
||||
raw.append(Z(UInt16(0)))
|
||||
raw.append(Z(UInt16(0)))
|
||||
}
|
||||
|
||||
// peer info
|
||||
raw.appendSized(Z(CoreConfiguration.peerInfo))
|
||||
|
|
|
@ -38,6 +38,29 @@
|
|||
import Foundation
|
||||
|
||||
extension SessionProxy {
|
||||
|
||||
/// A pair of credentials for authentication.
|
||||
public struct Credentials: Codable, Equatable {
|
||||
|
||||
/// The username.
|
||||
public let username: String
|
||||
|
||||
/// The password.
|
||||
public let password: String
|
||||
|
||||
/// :nodoc
|
||||
public init(_ username: String, _ password: String) {
|
||||
self.username = username
|
||||
self.password = password
|
||||
}
|
||||
|
||||
// MARK: Equatable
|
||||
|
||||
/// :nodoc:
|
||||
public static func ==(lhs: Credentials, rhs: Credentials) -> Bool {
|
||||
return (lhs.username == rhs.username) && (lhs.password == rhs.password)
|
||||
}
|
||||
}
|
||||
|
||||
/// The available encryption algorithms.
|
||||
public enum Cipher: String, Codable, CustomStringConvertible {
|
||||
|
@ -112,11 +135,8 @@ extension SessionProxy {
|
|||
/// The way to create a `SessionProxy.Configuration` object for a `SessionProxy`.
|
||||
public struct ConfigurationBuilder {
|
||||
|
||||
/// An username.
|
||||
public let username: String
|
||||
|
||||
/// A password.
|
||||
public let password: String
|
||||
/// The credentials.
|
||||
public var credentials: Credentials?
|
||||
|
||||
/// The cipher algorithm for data encryption.
|
||||
public var cipher: Cipher
|
||||
|
@ -124,8 +144,8 @@ extension SessionProxy {
|
|||
/// The digest algorithm for HMAC.
|
||||
public var digest: Digest
|
||||
|
||||
/// The path to the optional CA for TLS negotiation (PEM format).
|
||||
public var caPath: String?
|
||||
/// The path to the CA for TLS negotiation (PEM format).
|
||||
public let caPath: String
|
||||
|
||||
/// The path to the optional client certificate for TLS negotiation (PEM format).
|
||||
public var clientCertificatePath: String?
|
||||
|
@ -143,12 +163,11 @@ extension SessionProxy {
|
|||
public var renegotiatesAfter: TimeInterval?
|
||||
|
||||
/// :nodoc:
|
||||
public init(username: String, password: String) {
|
||||
self.username = username
|
||||
self.password = password
|
||||
public init(caPath: String) {
|
||||
credentials = nil
|
||||
cipher = .aes128cbc
|
||||
digest = .sha1
|
||||
caPath = nil
|
||||
self.caPath = caPath
|
||||
clientCertificatePath = nil
|
||||
clientKeyPath = nil
|
||||
compressionFraming = .disabled
|
||||
|
@ -163,8 +182,7 @@ extension SessionProxy {
|
|||
*/
|
||||
public func build() -> Configuration {
|
||||
return Configuration(
|
||||
username: username,
|
||||
password: password,
|
||||
credentials: credentials,
|
||||
cipher: cipher,
|
||||
digest: digest,
|
||||
caPath: caPath,
|
||||
|
@ -180,11 +198,8 @@ extension SessionProxy {
|
|||
/// The immutable configuration for `SessionProxy`.
|
||||
public struct Configuration: Codable {
|
||||
|
||||
/// - Seealso: `SessionProxy.ConfigurationBuilder.username`
|
||||
public let username: String
|
||||
|
||||
/// - Seealso: `SessionProxy.ConfigurationBuilder.password`
|
||||
public let password: String
|
||||
/// - Seealso: `SessionProxy.ConfigurationBuilder.credentials`
|
||||
public let credentials: Credentials?
|
||||
|
||||
/// - Seealso: `SessionProxy.ConfigurationBuilder.cipher`
|
||||
public let cipher: Cipher
|
||||
|
@ -193,7 +208,7 @@ extension SessionProxy {
|
|||
public let digest: Digest
|
||||
|
||||
/// - Seealso: `SessionProxy.ConfigurationBuilder.caPath`
|
||||
public let caPath: String?
|
||||
public let caPath: String
|
||||
|
||||
/// - Seealso: `SessionProxy.ConfigurationBuilder.clientCertificatePath`
|
||||
public let clientCertificatePath: String?
|
||||
|
|
|
@ -583,7 +583,7 @@ public class SessionProxy {
|
|||
negotiationKey.controlState = .preAuth
|
||||
|
||||
do {
|
||||
authenticator = try Authenticator(configuration.username, pushReply?.authToken ?? configuration.password)
|
||||
authenticator = try Authenticator(configuration.credentials?.username, pushReply?.authToken ?? configuration.credentials?.password)
|
||||
try authenticator?.putAuth(into: negotiationKey.tls)
|
||||
} catch let e {
|
||||
deferStop(.shutdown, e)
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
extern const NSInteger TLSBoxMaxBufferLength;
|
||||
|
||||
extern NSString *const TLSBoxPeerVerificationErrorNotification;
|
||||
|
@ -50,12 +52,12 @@ extern NSString *const TLSBoxPeerVerificationErrorNotification;
|
|||
@interface TLSBox : NSObject
|
||||
|
||||
- (instancetype)initWithCAPath:(NSString *)caPath
|
||||
clientCertificatePath:(NSString *)clientCertificatePath
|
||||
clientKeyPath:(NSString *)clientKeyPath;
|
||||
clientCertificatePath:(nullable NSString *)clientCertificatePath
|
||||
clientKeyPath:(nullable NSString *)clientKeyPath;
|
||||
|
||||
- (BOOL)startWithError:(NSError **)error;
|
||||
|
||||
- (NSData *)pullCipherTextWithError:(NSError **)error;
|
||||
- (nullable NSData *)pullCipherTextWithError:(NSError **)error;
|
||||
// WARNING: text must be able to hold plain text output
|
||||
- (BOOL)pullRawPlainText:(uint8_t *)text length:(NSInteger *)length error:(NSError **)error;
|
||||
|
||||
|
@ -67,3 +69,5 @@ extern NSString *const TLSBoxPeerVerificationErrorNotification;
|
|||
- (BOOL)isConnected;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -77,7 +77,8 @@ int TLSBoxVerifyPeer(int ok, X509_STORE_CTX *ctx) {
|
|||
|
||||
- (instancetype)init
|
||||
{
|
||||
return [self initWithCAPath:nil clientCertificatePath:nil clientKeyPath:nil];
|
||||
[NSException raise:NSInvalidArgumentException format:@"Use initWithCAPath:clientCertificatePath:clientKeyPath:"];
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCAPath:(NSString *)caPath clientCertificatePath:(NSString *)clientCertificatePath clientKeyPath:(NSString *)clientKeyPath
|
||||
|
@ -115,18 +116,13 @@ int TLSBoxVerifyPeer(int ok, X509_STORE_CTX *ctx) {
|
|||
|
||||
self.ctx = SSL_CTX_new(TLS_client_method());
|
||||
SSL_CTX_set_options(self.ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION);
|
||||
if (self.caPath) {
|
||||
SSL_CTX_set_verify(self.ctx, SSL_VERIFY_PEER, TLSBoxVerifyPeer);
|
||||
if (!SSL_CTX_load_verify_locations(self.ctx, [self.caPath cStringUsingEncoding:NSASCIIStringEncoding], NULL)) {
|
||||
ERR_print_errors_fp(stdout);
|
||||
if (error) {
|
||||
*error = TunnelKitErrorWithCode(TunnelKitErrorCodeTLSBoxCA);
|
||||
}
|
||||
return NO;
|
||||
SSL_CTX_set_verify(self.ctx, SSL_VERIFY_PEER, TLSBoxVerifyPeer);
|
||||
if (!SSL_CTX_load_verify_locations(self.ctx, [self.caPath cStringUsingEncoding:NSASCIIStringEncoding], NULL)) {
|
||||
ERR_print_errors_fp(stdout);
|
||||
if (error) {
|
||||
*error = TunnelKitErrorWithCode(TunnelKitErrorCodeTLSBoxCA);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SSL_CTX_set_verify(self.ctx, SSL_VERIFY_NONE, NULL);
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (self.clientCertificatePath) {
|
||||
|
|
|
@ -57,27 +57,23 @@ class AppExtensionTests: XCTestCase {
|
|||
|
||||
let identifier = "com.example.Provider"
|
||||
let appGroup = "group.com.algoritmico.TunnelKit"
|
||||
let endpoint = TunnelKitProvider.AuthenticatedEndpoint(
|
||||
hostname: "example.com",
|
||||
username: "foo",
|
||||
password: "bar"
|
||||
)
|
||||
let hostname = "example.com"
|
||||
let credentials = SessionProxy.Credentials("foo", "bar")
|
||||
|
||||
builder = TunnelKitProvider.ConfigurationBuilder()
|
||||
builder = TunnelKitProvider.ConfigurationBuilder(ca: CryptoContainer(pem: "abcdef"))
|
||||
XCTAssertNotNil(builder)
|
||||
|
||||
builder.cipher = .aes128cbc
|
||||
builder.digest = .sha256
|
||||
builder.ca = CryptoContainer(pem: "abcdef")
|
||||
cfg = builder.build()
|
||||
|
||||
let proto = try? cfg.generatedTunnelProtocol(withBundleIdentifier: identifier, appGroup: appGroup, endpoint: endpoint)
|
||||
let proto = try? cfg.generatedTunnelProtocol(withBundleIdentifier: identifier, appGroup: appGroup, hostname: hostname, credentials: credentials)
|
||||
XCTAssertNotNil(proto)
|
||||
|
||||
XCTAssertEqual(proto?.providerBundleIdentifier, identifier)
|
||||
XCTAssertEqual(proto?.serverAddress, endpoint.hostname)
|
||||
XCTAssertEqual(proto?.username, endpoint.username)
|
||||
XCTAssertEqual(proto?.passwordReference, try? Keychain(group: appGroup).passwordReference(for: endpoint.username))
|
||||
XCTAssertEqual(proto?.serverAddress, hostname)
|
||||
XCTAssertEqual(proto?.username, credentials.username)
|
||||
XCTAssertEqual(proto?.passwordReference, try? Keychain(group: appGroup).passwordReference(for: credentials.username))
|
||||
|
||||
if let pc = proto?.providerConfiguration {
|
||||
print("\(pc)")
|
||||
|
@ -87,7 +83,7 @@ class AppExtensionTests: XCTestCase {
|
|||
XCTAssertEqual(proto?.providerConfiguration?[K.appGroup] as? String, appGroup)
|
||||
XCTAssertEqual(proto?.providerConfiguration?[K.cipherAlgorithm] as? String, cfg.cipher.rawValue)
|
||||
XCTAssertEqual(proto?.providerConfiguration?[K.digestAlgorithm] as? String, cfg.digest.rawValue)
|
||||
XCTAssertEqual(proto?.providerConfiguration?[K.ca] as? String, cfg.ca?.pem)
|
||||
XCTAssertEqual(proto?.providerConfiguration?[K.ca] as? String, cfg.ca.pem)
|
||||
XCTAssertEqual(proto?.providerConfiguration?[K.mtu] as? Int, cfg.mtu)
|
||||
XCTAssertEqual(proto?.providerConfiguration?[K.renegotiatesAfter] as? Int, cfg.renegotiatesAfterSeconds)
|
||||
XCTAssertEqual(proto?.providerConfiguration?[K.debug] as? Bool, cfg.shouldDebug)
|
||||
|
|
Loading…
Reference in New Issue