Enforce use of non-preset CA certificates
This commit is contained in:
parent
dfac465c1d
commit
897e824340
|
@ -23,4 +23,5 @@ custom_categories:
|
||||||
- SessionError
|
- SessionError
|
||||||
- name: AppExtension
|
- name: AppExtension
|
||||||
children:
|
children:
|
||||||
|
- Certificate
|
||||||
- TunnelKitProvider
|
- TunnelKitProvider
|
||||||
|
|
|
@ -62,6 +62,8 @@
|
||||||
0EC1BBA620D712DE007C4C7B /* DNSResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC1BBA420D71190007C4C7B /* DNSResolver.swift */; };
|
0EC1BBA620D712DE007C4C7B /* DNSResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC1BBA420D71190007C4C7B /* DNSResolver.swift */; };
|
||||||
0EC1BBA820D7D803007C4C7B /* ConnectionStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC1BBA720D7D803007C4C7B /* ConnectionStrategy.swift */; };
|
0EC1BBA820D7D803007C4C7B /* ConnectionStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC1BBA720D7D803007C4C7B /* ConnectionStrategy.swift */; };
|
||||||
0EC1BBA920D7D803007C4C7B /* ConnectionStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC1BBA720D7D803007C4C7B /* ConnectionStrategy.swift */; };
|
0EC1BBA920D7D803007C4C7B /* ConnectionStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC1BBA720D7D803007C4C7B /* ConnectionStrategy.swift */; };
|
||||||
|
0ECE3528212EB7770040F253 /* Certificate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECE3527212EB7770040F253 /* Certificate.swift */; };
|
||||||
|
0ECE352A212EB88E0040F253 /* Certificate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECE3527212EB7770040F253 /* Certificate.swift */; };
|
||||||
0EE7A79520F61EDC00B42E6A /* PacketMacros.h in Sources */ = {isa = PBXBuildFile; fileRef = 0EE7A79420F61EDC00B42E6A /* PacketMacros.h */; };
|
0EE7A79520F61EDC00B42E6A /* PacketMacros.h in Sources */ = {isa = PBXBuildFile; fileRef = 0EE7A79420F61EDC00B42E6A /* PacketMacros.h */; };
|
||||||
0EE7A79620F61EDC00B42E6A /* PacketMacros.h in Sources */ = {isa = PBXBuildFile; fileRef = 0EE7A79420F61EDC00B42E6A /* PacketMacros.h */; };
|
0EE7A79620F61EDC00B42E6A /* PacketMacros.h in Sources */ = {isa = PBXBuildFile; fileRef = 0EE7A79420F61EDC00B42E6A /* PacketMacros.h */; };
|
||||||
0EE7A79820F6296F00B42E6A /* PacketMacros.m in Sources */ = {isa = PBXBuildFile; fileRef = 0EE7A79720F6296F00B42E6A /* PacketMacros.m */; };
|
0EE7A79820F6296F00B42E6A /* PacketMacros.m in Sources */ = {isa = PBXBuildFile; fileRef = 0EE7A79720F6296F00B42E6A /* PacketMacros.m */; };
|
||||||
|
@ -213,6 +215,7 @@
|
||||||
0EBBF2FF2085196000E36B40 /* NWTCPConnectionState+Description.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NWTCPConnectionState+Description.swift"; sourceTree = "<group>"; };
|
0EBBF2FF2085196000E36B40 /* NWTCPConnectionState+Description.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NWTCPConnectionState+Description.swift"; sourceTree = "<group>"; };
|
||||||
0EC1BBA420D71190007C4C7B /* DNSResolver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DNSResolver.swift; sourceTree = "<group>"; };
|
0EC1BBA420D71190007C4C7B /* DNSResolver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DNSResolver.swift; sourceTree = "<group>"; };
|
||||||
0EC1BBA720D7D803007C4C7B /* ConnectionStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionStrategy.swift; sourceTree = "<group>"; };
|
0EC1BBA720D7D803007C4C7B /* ConnectionStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionStrategy.swift; sourceTree = "<group>"; };
|
||||||
|
0ECE3527212EB7770040F253 /* Certificate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Certificate.swift; sourceTree = "<group>"; };
|
||||||
0EE7A79420F61EDC00B42E6A /* PacketMacros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PacketMacros.h; sourceTree = "<group>"; };
|
0EE7A79420F61EDC00B42E6A /* PacketMacros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PacketMacros.h; sourceTree = "<group>"; };
|
||||||
0EE7A79720F6296F00B42E6A /* PacketMacros.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PacketMacros.m; sourceTree = "<group>"; };
|
0EE7A79720F6296F00B42E6A /* PacketMacros.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PacketMacros.m; sourceTree = "<group>"; };
|
||||||
0EE7A79D20F6488400B42E6A /* DataPathEncryption.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DataPathEncryption.h; sourceTree = "<group>"; };
|
0EE7A79D20F6488400B42E6A /* DataPathEncryption.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DataPathEncryption.h; sourceTree = "<group>"; };
|
||||||
|
@ -459,6 +462,7 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
0EBBF2E32084FDF400E36B40 /* Transport */,
|
0EBBF2E32084FDF400E36B40 /* Transport */,
|
||||||
|
0ECE3527212EB7770040F253 /* Certificate.swift */,
|
||||||
0EC1BBA720D7D803007C4C7B /* ConnectionStrategy.swift */,
|
0EC1BBA720D7D803007C4C7B /* ConnectionStrategy.swift */,
|
||||||
0EC1BBA420D71190007C4C7B /* DNSResolver.swift */,
|
0EC1BBA420D71190007C4C7B /* DNSResolver.swift */,
|
||||||
0EBBF2E42084FE6F00E36B40 /* GenericSocket.swift */,
|
0EBBF2E42084FE6F00E36B40 /* GenericSocket.swift */,
|
||||||
|
@ -887,6 +891,7 @@
|
||||||
0EFEB4AC200760EC00F81029 /* InterfaceObserver.swift in Sources */,
|
0EFEB4AC200760EC00F81029 /* InterfaceObserver.swift in Sources */,
|
||||||
0EFEB46D2006D3C800F81029 /* Data+Manipulation.swift in Sources */,
|
0EFEB46D2006D3C800F81029 /* Data+Manipulation.swift in Sources */,
|
||||||
0EFEB47B2006D3C800F81029 /* TunnelKitProvider.swift in Sources */,
|
0EFEB47B2006D3C800F81029 /* TunnelKitProvider.swift in Sources */,
|
||||||
|
0ECE3528212EB7770040F253 /* Certificate.swift in Sources */,
|
||||||
0EFEB4742006D3C800F81029 /* CoreConfiguration.swift in Sources */,
|
0EFEB4742006D3C800F81029 /* CoreConfiguration.swift in Sources */,
|
||||||
0E07595F20EF6D1400F38FD8 /* CryptoCBC.m in Sources */,
|
0E07595F20EF6D1400F38FD8 /* CryptoCBC.m in Sources */,
|
||||||
0EC1BBA820D7D803007C4C7B /* ConnectionStrategy.swift in Sources */,
|
0EC1BBA820D7D803007C4C7B /* ConnectionStrategy.swift in Sources */,
|
||||||
|
@ -935,6 +940,7 @@
|
||||||
0EFEB4A22006D7F300F81029 /* CoreConfiguration.swift in Sources */,
|
0EFEB4A22006D7F300F81029 /* CoreConfiguration.swift in Sources */,
|
||||||
0EFEB4952006D7F300F81029 /* SecureRandom.swift in Sources */,
|
0EFEB4952006D7F300F81029 /* SecureRandom.swift in Sources */,
|
||||||
0EFEB49A2006D7F300F81029 /* MSS.m in Sources */,
|
0EFEB49A2006D7F300F81029 /* MSS.m in Sources */,
|
||||||
|
0ECE352A212EB88E0040F253 /* Certificate.swift in Sources */,
|
||||||
0EFEB48D2006D7F300F81029 /* EncryptionProxy.swift in Sources */,
|
0EFEB48D2006D7F300F81029 /* EncryptionProxy.swift in Sources */,
|
||||||
0EFEB4922006D7F300F81029 /* ZeroingData.m in Sources */,
|
0EFEB4922006D7F300F81029 /* ZeroingData.m in Sources */,
|
||||||
0E07596020EF6D1400F38FD8 /* CryptoCBC.m in Sources */,
|
0E07596020EF6D1400F38FD8 /* CryptoCBC.m in Sources */,
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
//
|
||||||
|
// Certificate.swift
|
||||||
|
// TunnelKit
|
||||||
|
//
|
||||||
|
// Created by Davide De Rosa on 22/08/2018.
|
||||||
|
// Copyright © 2018 Davide De Rosa. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// Represents a TLS certificate in PEM format.
|
||||||
|
public struct Certificate: Equatable {
|
||||||
|
|
||||||
|
/// The content of the certificates in PEM format (ASCII).
|
||||||
|
public let pem: String
|
||||||
|
|
||||||
|
/// :nodoc:
|
||||||
|
public init(pem: String) {
|
||||||
|
self.pem = pem
|
||||||
|
}
|
||||||
|
|
||||||
|
func write(to url: URL) throws {
|
||||||
|
try pem.write(to: url, atomically: true, encoding: .ascii)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Equatable
|
||||||
|
|
||||||
|
/// :nodoc:
|
||||||
|
public static func ==(lhs: Certificate, rhs: Certificate) -> Bool {
|
||||||
|
return lhs.pem == rhs.pem
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,64 +45,6 @@ extension TunnelKitProvider {
|
||||||
/// SHA256 message digest.
|
/// SHA256 message digest.
|
||||||
case sha256 = "SHA256"
|
case sha256 = "SHA256"
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The available certificates for handshake.
|
|
||||||
public enum Handshake: String {
|
|
||||||
|
|
||||||
/// Certificate with RSA 2048-bit key.
|
|
||||||
case rsa2048 = "RSA-2048"
|
|
||||||
|
|
||||||
/// Certificate with RSA 3072-bit key.
|
|
||||||
case rsa3072 = "RSA-3072"
|
|
||||||
|
|
||||||
/// Certificate with RSA 4096-bit key.
|
|
||||||
case rsa4096 = "RSA-4096"
|
|
||||||
|
|
||||||
/// Certificate with ECC based on secp256r1 curve.
|
|
||||||
case ecc256r1 = "ECC-256r1"
|
|
||||||
|
|
||||||
/// Certificate with ECC based on secp256k1 curve.
|
|
||||||
case ecc256k1 = "ECC-256k1"
|
|
||||||
|
|
||||||
/// Certificate with ECC based on secp521r1 curve.
|
|
||||||
case ecc521r1 = "ECC-521r1"
|
|
||||||
|
|
||||||
/// Custom certificate.
|
|
||||||
///
|
|
||||||
/// - Seealso:
|
|
||||||
case custom = "Custom"
|
|
||||||
|
|
||||||
private static let allDigests: [Handshake: String] = [
|
|
||||||
.rsa2048: "e2fccccaba712ccc68449b1c56427ac1",
|
|
||||||
.rsa3072: "2fcdb65712df9db7dae34a1f4a84e32d",
|
|
||||||
.rsa4096: "ec085790314aa0ad4b01dda7b756a932",
|
|
||||||
.ecc256r1: "6f0f23a616479329ce54614f76b52254",
|
|
||||||
.ecc256k1: "80c3b0f34001e4101e34fde9eb1dfa87",
|
|
||||||
.ecc521r1: "82446e0c80706e33e6e793cebf1b0c59"
|
|
||||||
]
|
|
||||||
|
|
||||||
var digest: String? {
|
|
||||||
return Handshake.allDigests[self]
|
|
||||||
}
|
|
||||||
|
|
||||||
func write(to url: URL, custom: String? = nil) throws {
|
|
||||||
precondition((self != .custom) || (custom != nil))
|
|
||||||
|
|
||||||
// custom certificate?
|
|
||||||
if self == .custom, let content = custom {
|
|
||||||
try content.write(to: url, atomically: true, encoding: .ascii)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let bundle = Bundle(for: TunnelKitProvider.self)
|
|
||||||
let certName = "PIA-\(rawValue)"
|
|
||||||
guard let certUrl = bundle.url(forResource: certName, withExtension: "pem") else {
|
|
||||||
fatalError("Could not find \(certName) TLS certificate")
|
|
||||||
}
|
|
||||||
let content = try String(contentsOf: certUrl)
|
|
||||||
try content.write(to: url, atomically: true, encoding: .ascii)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TunnelKitProvider {
|
extension TunnelKitProvider {
|
||||||
|
@ -215,16 +157,13 @@ extension TunnelKitProvider {
|
||||||
/// The message digest algorithm.
|
/// The message digest algorithm.
|
||||||
public var digest: Digest
|
public var digest: Digest
|
||||||
|
|
||||||
/// The handshake certificate.
|
/// The optional CA certificate to validate server against. Set to `nil` to disable CA validation (default).
|
||||||
public var handshake: Handshake
|
public var ca: Certificate?
|
||||||
|
|
||||||
/// The custom CA certificate in PEM format in case `handshake == .custom`. Ignored otherwise.
|
|
||||||
public var ca: String?
|
|
||||||
|
|
||||||
/// The MTU of the tunnel.
|
/// The MTU of the tunnel.
|
||||||
public var mtu: NSNumber
|
public var mtu: NSNumber
|
||||||
|
|
||||||
/// The number of seconds after which a renegotiation is started. Set to `nil` to disable renegotiation.
|
/// The number of seconds after which a renegotiation is started. Set to `nil` to disable renegotiation (default).
|
||||||
public var renegotiatesAfterSeconds: Int?
|
public var renegotiatesAfterSeconds: Int?
|
||||||
|
|
||||||
// MARK: Debugging
|
// MARK: Debugging
|
||||||
|
@ -252,7 +191,6 @@ extension TunnelKitProvider {
|
||||||
endpointProtocols = [EndpointProtocol(.udp, 1194)]
|
endpointProtocols = [EndpointProtocol(.udp, 1194)]
|
||||||
cipher = .aes128cbc
|
cipher = .aes128cbc
|
||||||
digest = .sha1
|
digest = .sha1
|
||||||
handshake = .rsa2048
|
|
||||||
ca = nil
|
ca = nil
|
||||||
mtu = 1500
|
mtu = 1500
|
||||||
renegotiatesAfterSeconds = nil
|
renegotiatesAfterSeconds = nil
|
||||||
|
@ -274,20 +212,12 @@ extension TunnelKitProvider {
|
||||||
throw ProviderError.configuration(field: "protocolConfiguration.providerConfiguration[\(S.digestAlgorithm)]")
|
throw ProviderError.configuration(field: "protocolConfiguration.providerConfiguration[\(S.digestAlgorithm)]")
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallback to .rsa2048 in < 0.7 configurations (ca/caDigest)
|
let ca: Certificate?
|
||||||
let fallbackHandshake: Handshake = .rsa2048
|
if let caPEM = providerConfiguration[S.ca] as? String {
|
||||||
var handshake: Handshake = fallbackHandshake
|
ca = Certificate(pem: caPEM)
|
||||||
if let handshakeCertificate = providerConfiguration[S.handshakeCertificate] as? String {
|
} else {
|
||||||
handshake = Handshake(rawValue: handshakeCertificate) ?? fallbackHandshake
|
ca = nil
|
||||||
}
|
}
|
||||||
if handshake == .custom {
|
|
||||||
guard let ca = providerConfiguration[S.ca] as? String else {
|
|
||||||
throw ProviderError.configuration(field: "protocolConfiguration.providerConfiguration[\(S.ca)]")
|
|
||||||
}
|
|
||||||
self.ca = ca
|
|
||||||
}
|
|
||||||
|
|
||||||
self.appGroup = appGroup
|
|
||||||
|
|
||||||
prefersResolvedAddresses = providerConfiguration[S.prefersResolvedAddresses] as? Bool ?? false
|
prefersResolvedAddresses = providerConfiguration[S.prefersResolvedAddresses] as? Bool ?? false
|
||||||
resolvedAddresses = providerConfiguration[S.resolvedAddresses] as? [String]
|
resolvedAddresses = providerConfiguration[S.resolvedAddresses] as? [String]
|
||||||
|
@ -310,9 +240,10 @@ extension TunnelKitProvider {
|
||||||
return EndpointProtocol(socketType, port)
|
return EndpointProtocol(socketType, port)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.appGroup = appGroup
|
||||||
self.cipher = cipher
|
self.cipher = cipher
|
||||||
self.digest = digest
|
self.digest = digest
|
||||||
self.handshake = handshake
|
self.ca = ca
|
||||||
mtu = providerConfiguration[S.mtu] as? NSNumber ?? 1500
|
mtu = providerConfiguration[S.mtu] as? NSNumber ?? 1500
|
||||||
renegotiatesAfterSeconds = providerConfiguration[S.renegotiatesAfter] as? Int
|
renegotiatesAfterSeconds = providerConfiguration[S.renegotiatesAfter] as? Int
|
||||||
|
|
||||||
|
@ -345,7 +276,6 @@ extension TunnelKitProvider {
|
||||||
endpointProtocols: endpointProtocols,
|
endpointProtocols: endpointProtocols,
|
||||||
cipher: cipher,
|
cipher: cipher,
|
||||||
digest: digest,
|
digest: digest,
|
||||||
handshake: handshake,
|
|
||||||
ca: ca,
|
ca: ca,
|
||||||
mtu: mtu,
|
mtu: mtu,
|
||||||
renegotiatesAfterSeconds: renegotiatesAfterSeconds,
|
renegotiatesAfterSeconds: renegotiatesAfterSeconds,
|
||||||
|
@ -371,8 +301,6 @@ extension TunnelKitProvider {
|
||||||
|
|
||||||
static let digestAlgorithm = "DigestAlgorithm"
|
static let digestAlgorithm = "DigestAlgorithm"
|
||||||
|
|
||||||
static let handshakeCertificate = "HandshakeCertificate"
|
|
||||||
|
|
||||||
static let ca = "CA"
|
static let ca = "CA"
|
||||||
|
|
||||||
static let mtu = "MTU"
|
static let mtu = "MTU"
|
||||||
|
@ -404,11 +332,8 @@ extension TunnelKitProvider {
|
||||||
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.digest`
|
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.digest`
|
||||||
public let digest: Digest
|
public let digest: Digest
|
||||||
|
|
||||||
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.handshake`
|
|
||||||
public let handshake: Handshake
|
|
||||||
|
|
||||||
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.ca`
|
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.ca`
|
||||||
public let ca: String?
|
public let ca: Certificate?
|
||||||
|
|
||||||
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.mtu`
|
/// - Seealso: `TunnelKitProvider.ConfigurationBuilder.mtu`
|
||||||
public let mtu: NSNumber
|
public let mtu: NSNumber
|
||||||
|
@ -468,12 +393,11 @@ extension TunnelKitProvider {
|
||||||
},
|
},
|
||||||
S.cipherAlgorithm: cipher.rawValue,
|
S.cipherAlgorithm: cipher.rawValue,
|
||||||
S.digestAlgorithm: digest.rawValue,
|
S.digestAlgorithm: digest.rawValue,
|
||||||
S.handshakeCertificate: handshake.rawValue,
|
|
||||||
S.mtu: mtu,
|
S.mtu: mtu,
|
||||||
S.debug: shouldDebug
|
S.debug: shouldDebug
|
||||||
]
|
]
|
||||||
if let ca = ca {
|
if let ca = ca {
|
||||||
dict[S.ca] = ca
|
dict[S.ca] = ca.pem
|
||||||
}
|
}
|
||||||
if let resolvedAddresses = resolvedAddresses {
|
if let resolvedAddresses = resolvedAddresses {
|
||||||
dict[S.resolvedAddresses] = resolvedAddresses
|
dict[S.resolvedAddresses] = resolvedAddresses
|
||||||
|
@ -526,7 +450,11 @@ extension TunnelKitProvider {
|
||||||
log.info("Protocols: \(endpointProtocols)")
|
log.info("Protocols: \(endpointProtocols)")
|
||||||
log.info("Cipher: \(cipher.rawValue)")
|
log.info("Cipher: \(cipher.rawValue)")
|
||||||
log.info("Digest: \(digest.rawValue)")
|
log.info("Digest: \(digest.rawValue)")
|
||||||
log.info("Handshake: \(handshake.rawValue)")
|
if let _ = ca {
|
||||||
|
log.info("CA verification: enabled")
|
||||||
|
} else {
|
||||||
|
log.info("CA verification: disabled")
|
||||||
|
}
|
||||||
log.info("MTU: \(mtu)")
|
log.info("MTU: \(mtu)")
|
||||||
if let renegotiatesAfterSeconds = renegotiatesAfterSeconds {
|
if let renegotiatesAfterSeconds = renegotiatesAfterSeconds {
|
||||||
log.info("Renegotiation: \(renegotiatesAfterSeconds) seconds")
|
log.info("Renegotiation: \(renegotiatesAfterSeconds) seconds")
|
||||||
|
@ -552,7 +480,7 @@ extension TunnelKitProvider.Configuration: Equatable {
|
||||||
builder.endpointProtocols = endpointProtocols
|
builder.endpointProtocols = endpointProtocols
|
||||||
builder.cipher = cipher
|
builder.cipher = cipher
|
||||||
builder.digest = digest
|
builder.digest = digest
|
||||||
builder.handshake = handshake
|
builder.ca = ca
|
||||||
builder.mtu = mtu
|
builder.mtu = mtu
|
||||||
builder.renegotiatesAfterSeconds = renegotiatesAfterSeconds
|
builder.renegotiatesAfterSeconds = renegotiatesAfterSeconds
|
||||||
builder.shouldDebug = shouldDebug
|
builder.shouldDebug = shouldDebug
|
||||||
|
@ -566,7 +494,7 @@ extension TunnelKitProvider.Configuration: Equatable {
|
||||||
(lhs.endpointProtocols == rhs.endpointProtocols) &&
|
(lhs.endpointProtocols == rhs.endpointProtocols) &&
|
||||||
(lhs.cipher == rhs.cipher) &&
|
(lhs.cipher == rhs.cipher) &&
|
||||||
(lhs.digest == rhs.digest) &&
|
(lhs.digest == rhs.digest) &&
|
||||||
(lhs.handshake == rhs.handshake) &&
|
(lhs.ca == rhs.ca) &&
|
||||||
(lhs.mtu == rhs.mtu) &&
|
(lhs.mtu == rhs.mtu) &&
|
||||||
(lhs.renegotiatesAfterSeconds == rhs.renegotiatesAfterSeconds)
|
(lhs.renegotiatesAfterSeconds == rhs.renegotiatesAfterSeconds)
|
||||||
)
|
)
|
||||||
|
|
|
@ -139,18 +139,23 @@ open class TunnelKitProvider: NEPacketTunnelProvider {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
let caPath: String?
|
||||||
try cfg.handshake.write(to: tmpCaURL, custom: cfg.ca)
|
if let ca = cfg.ca {
|
||||||
} catch {
|
do {
|
||||||
completionHandler(ProviderError.certificateSerialization)
|
try ca.write(to: tmpCaURL)
|
||||||
return
|
caPath = tmpCaURL.path
|
||||||
|
} catch {
|
||||||
|
completionHandler(ProviderError.certificateSerialization)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
caPath = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.print(appVersion: appVersion)
|
cfg.print(appVersion: appVersion)
|
||||||
|
|
||||||
let caPath = tmpCaURL.path
|
|
||||||
// log.info("Temporary CA is stored to: \(caPath)")
|
// log.info("Temporary CA is stored to: \(caPath)")
|
||||||
let encryption = SessionProxy.EncryptionParameters(cfg.cipher.rawValue, cfg.digest.rawValue, caPath, cfg.handshake.digest)
|
let encryption = SessionProxy.EncryptionParameters(cfg.cipher.rawValue, cfg.digest.rawValue, caPath)
|
||||||
let credentials = SessionProxy.Credentials(endpoint.username, endpoint.password)
|
let credentials = SessionProxy.Credentials(endpoint.username, endpoint.password)
|
||||||
|
|
||||||
let proxy: SessionProxy
|
let proxy: SessionProxy
|
||||||
|
|
|
@ -91,17 +91,13 @@ public class SessionProxy {
|
||||||
public let digestName: String
|
public let digestName: String
|
||||||
|
|
||||||
/// The path to the CA for TLS negotiation (PEM format).
|
/// The path to the CA for TLS negotiation (PEM format).
|
||||||
public let caPath: String
|
public let caPath: String?
|
||||||
|
|
||||||
/// The MD5 digest of the CA (computed from DER format).
|
|
||||||
public let caDigest: String?
|
|
||||||
|
|
||||||
/// :nodoc:
|
/// :nodoc:
|
||||||
public init(_ cipherName: String, _ digestName: String, _ caPath: String, _ caDigest: String?) {
|
public init(_ cipherName: String, _ digestName: String, _ caPath: String?) {
|
||||||
self.cipherName = cipherName
|
self.cipherName = cipherName
|
||||||
self.digestName = digestName
|
self.digestName = digestName
|
||||||
self.caPath = caPath
|
self.caPath = caPath
|
||||||
self.caDigest = caDigest
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -834,7 +830,7 @@ public class SessionProxy {
|
||||||
|
|
||||||
negotiationKey.tlsOptional = TLSBox(caPath: encryption.caPath)
|
negotiationKey.tlsOptional = TLSBox(caPath: encryption.caPath)
|
||||||
do {
|
do {
|
||||||
try negotiationKey.tls.start(withPeerVerification: true)
|
try negotiationKey.tls.start()
|
||||||
} catch let e {
|
} catch let e {
|
||||||
deferStop(.shutdown, e)
|
deferStop(.shutdown, e)
|
||||||
return
|
return
|
||||||
|
|
|
@ -20,9 +20,9 @@ extern NSString *const TLSBoxPeerVerificationErrorNotification;
|
||||||
//
|
//
|
||||||
@interface TLSBox : NSObject
|
@interface TLSBox : NSObject
|
||||||
|
|
||||||
- (nonnull instancetype)initWithCAPath:(NSString *)caPath;
|
- (nonnull instancetype)initWithCAPath:(nullable NSString *)caPath;
|
||||||
|
|
||||||
- (BOOL)startWithPeerVerification:(BOOL)peerVerification error:(NSError **)error;
|
- (BOOL)startWithError:(NSError **)error;
|
||||||
|
|
||||||
- (NSData *)pullCipherTextWithError:(NSError **)error;
|
- (NSData *)pullCipherTextWithError:(NSError **)error;
|
||||||
// WARNING: text must be able to hold plain text output
|
// WARNING: text must be able to hold plain text output
|
||||||
|
|
|
@ -74,7 +74,7 @@ int TLSBoxVerifyPeer(int ok, X509_STORE_CTX *ctx) {
|
||||||
free(self.bufferCipherText);
|
free(self.bufferCipherText);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)startWithPeerVerification:(BOOL)peerVerification error:(NSError *__autoreleasing *)error
|
- (BOOL)startWithError:(NSError *__autoreleasing *)error
|
||||||
{
|
{
|
||||||
if (!TLSBoxIsOpenSSLLoaded) {
|
if (!TLSBoxIsOpenSSLLoaded) {
|
||||||
// OPENSSL_init_ssl(0, NULL);
|
// OPENSSL_init_ssl(0, NULL);
|
||||||
|
@ -84,7 +84,7 @@ int TLSBoxVerifyPeer(int ok, X509_STORE_CTX *ctx) {
|
||||||
|
|
||||||
self.ctx = SSL_CTX_new(TLS_client_method());
|
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);
|
SSL_CTX_set_options(self.ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_COMPRESSION);
|
||||||
if (peerVerification && self.caPath) {
|
if (self.caPath) {
|
||||||
SSL_CTX_set_verify(self.ctx, SSL_VERIFY_PEER, TLSBoxVerifyPeer);
|
SSL_CTX_set_verify(self.ctx, SSL_VERIFY_PEER, TLSBoxVerifyPeer);
|
||||||
if (!SSL_CTX_load_verify_locations(self.ctx, [self.caPath cStringUsingEncoding:NSASCIIStringEncoding], NULL)) {
|
if (!SSL_CTX_load_verify_locations(self.ctx, [self.caPath cStringUsingEncoding:NSASCIIStringEncoding], NULL)) {
|
||||||
ERR_print_errors_fp(stdout);
|
ERR_print_errors_fp(stdout);
|
||||||
|
|
|
@ -39,7 +39,7 @@ class AppExtensionTests: XCTestCase {
|
||||||
|
|
||||||
builder.cipher = .aes128cbc
|
builder.cipher = .aes128cbc
|
||||||
builder.digest = .sha256
|
builder.digest = .sha256
|
||||||
builder.handshake = .rsa3072
|
builder.ca = Certificate(pem: "abcdef")
|
||||||
cfg = builder.build()
|
cfg = builder.build()
|
||||||
|
|
||||||
let proto = try? cfg.generatedTunnelProtocol(withBundleIdentifier: identifier, endpoint: endpoint)
|
let proto = try? cfg.generatedTunnelProtocol(withBundleIdentifier: identifier, endpoint: endpoint)
|
||||||
|
@ -58,7 +58,7 @@ class AppExtensionTests: XCTestCase {
|
||||||
XCTAssertEqual(proto?.providerConfiguration?[K.appGroup] as? String, cfg.appGroup)
|
XCTAssertEqual(proto?.providerConfiguration?[K.appGroup] as? String, cfg.appGroup)
|
||||||
XCTAssertEqual(proto?.providerConfiguration?[K.cipherAlgorithm] as? String, cfg.cipher.rawValue)
|
XCTAssertEqual(proto?.providerConfiguration?[K.cipherAlgorithm] as? String, cfg.cipher.rawValue)
|
||||||
XCTAssertEqual(proto?.providerConfiguration?[K.digestAlgorithm] as? String, cfg.digest.rawValue)
|
XCTAssertEqual(proto?.providerConfiguration?[K.digestAlgorithm] as? String, cfg.digest.rawValue)
|
||||||
XCTAssertEqual(proto?.providerConfiguration?[K.handshakeCertificate] as? String, cfg.handshake.rawValue)
|
XCTAssertEqual(proto?.providerConfiguration?[K.ca] as? String, cfg.ca?.pem)
|
||||||
XCTAssertEqual(proto?.providerConfiguration?[K.mtu] as? NSNumber, cfg.mtu)
|
XCTAssertEqual(proto?.providerConfiguration?[K.mtu] as? NSNumber, cfg.mtu)
|
||||||
XCTAssertEqual(proto?.providerConfiguration?[K.renegotiatesAfter] as? Int, cfg.renegotiatesAfterSeconds)
|
XCTAssertEqual(proto?.providerConfiguration?[K.renegotiatesAfter] as? Int, cfg.renegotiatesAfterSeconds)
|
||||||
XCTAssertEqual(proto?.providerConfiguration?[K.debug] as? Bool, cfg.shouldDebug)
|
XCTAssertEqual(proto?.providerConfiguration?[K.debug] as? Bool, cfg.shouldDebug)
|
||||||
|
|
Loading…
Reference in New Issue