diff --git a/CHANGELOG.md b/CHANGELOG.md index 61187dc..242a3ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Override DNS servers client side. [#56](https://github.com/keeshux/tunnelkit/pull/56) +### Changed + +- Enable or disable EKU according to `remote-cert-tls server` in .ovpn file. [#64](https://github.com/keeshux/tunnelkit/pull/64) + ### Fixed - Compiling errors in demo target. diff --git a/TunnelKit.xcodeproj/project.pbxproj b/TunnelKit.xcodeproj/project.pbxproj index 3e899ef..5c16040 100644 --- a/TunnelKit.xcodeproj/project.pbxproj +++ b/TunnelKit.xcodeproj/project.pbxproj @@ -1348,7 +1348,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 309; + CURRENT_PROJECT_VERSION = 329; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -1412,7 +1412,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 309; + CURRENT_PROJECT_VERSION = 329; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -1445,7 +1445,7 @@ DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 309; + DYLIB_CURRENT_VERSION = 329; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = "$(SRCROOT)/TunnelKit-iOS/Info.plist"; @@ -1468,7 +1468,7 @@ DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 309; + DYLIB_CURRENT_VERSION = 329; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = "$(SRCROOT)/TunnelKit-iOS/Info.plist"; @@ -1491,7 +1491,7 @@ COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 309; + DYLIB_CURRENT_VERSION = 329; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; INFOPLIST_FILE = "$(SRCROOT)/TunnelKit-macOS/Info.plist"; @@ -1514,7 +1514,7 @@ COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 309; + DYLIB_CURRENT_VERSION = 329; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; INFOPLIST_FILE = "$(SRCROOT)/TunnelKit-macOS/Info.plist"; diff --git a/TunnelKit/Sources/AppExtension/TunnelKitProvider+Configuration.swift b/TunnelKit/Sources/AppExtension/TunnelKitProvider+Configuration.swift index f253fc2..83c489f 100644 --- a/TunnelKit/Sources/AppExtension/TunnelKitProvider+Configuration.swift +++ b/TunnelKit/Sources/AppExtension/TunnelKitProvider+Configuration.swift @@ -60,6 +60,7 @@ extension TunnelKitProvider { ca: CryptoContainer(pem: ""), clientCertificate: nil, clientKey: nil, + checksEKU: false, compressionFraming: .disabled, tlsWrap: nil, keepAliveInterval: nil, @@ -465,6 +466,11 @@ extension TunnelKitProvider { } else { log.info("\tClient verification: disabled") } + if sessionConfiguration.checksEKU ?? false { + log.info("\tServer EKU verification: enabled") + } else { + log.info("\tServer EKU verification: disabled") + } log.info("\tMTU: \(mtu)") log.info("\tCompression framing: \(sessionConfiguration.compressionFraming)") if let keepAliveSeconds = sessionConfiguration.keepAliveInterval, keepAliveSeconds > 0 { diff --git a/TunnelKit/Sources/Core/ConfigurationParser.swift b/TunnelKit/Sources/Core/ConfigurationParser.swift index d3eee1b..c80665a 100644 --- a/TunnelKit/Sources/Core/ConfigurationParser.swift +++ b/TunnelKit/Sources/Core/ConfigurationParser.swift @@ -87,11 +87,13 @@ public class ConfigurationParser { static let keyDirection = NSRegularExpression("^key-direction +\\d") + static let eku = NSRegularExpression("^remote-cert-tls +server") + static let blockBegin = NSRegularExpression("^<[\\w\\-]+>") static let blockEnd = NSRegularExpression("^<\\/[\\w\\-]+>") - static let dnsRegexp = NSRegularExpression("dhcp-option DNS6? [\\d\\.a-fA-F:]+") + static let dns = NSRegularExpression("^dhcp-option +DNS6? +[\\d\\.a-fA-F:]+") // unsupported @@ -139,6 +141,7 @@ public class ConfigurationParser { var optCA: CryptoContainer? var clientCertificate: CryptoContainer? var clientKey: CryptoContainer? + var checksEKU = false var keepAliveSeconds: TimeInterval? var renegotiateAfterSeconds: TimeInterval? var keyDirection: StaticKey.Direction? @@ -218,6 +221,9 @@ public class ConfigurationParser { continue } + Regex.eku.enumerateComponents(in: line) { (_) in + checksEKU = true + } Regex.proto.enumerateArguments(in: line) { isHandled = true guard let str = $0.first else { @@ -319,7 +325,7 @@ public class ConfigurationParser { } renegotiateAfterSeconds = TimeInterval(arg) } - Regex.dnsRegexp.enumerateArguments(in: line) { + Regex.dns.enumerateArguments(in: line) { isHandled = true guard $0.count == 2 else { return @@ -399,6 +405,7 @@ public class ConfigurationParser { sessionBuilder.tlsWrap = tlsWrap sessionBuilder.clientCertificate = clientCertificate sessionBuilder.clientKey = clientKey + sessionBuilder.checksEKU = checksEKU sessionBuilder.keepAliveInterval = keepAliveSeconds sessionBuilder.renegotiatesAfter = renegotiateAfterSeconds sessionBuilder.dnsServers = dnsServers diff --git a/TunnelKit/Sources/Core/SessionProxy+Configuration.swift b/TunnelKit/Sources/Core/SessionProxy+Configuration.swift index 9bcd700..742c317 100644 --- a/TunnelKit/Sources/Core/SessionProxy+Configuration.swift +++ b/TunnelKit/Sources/Core/SessionProxy+Configuration.swift @@ -150,6 +150,9 @@ extension SessionProxy { /// The private key for the certificate in `clientCertificate` (PEM format). public var clientKey: CryptoContainer? + /// If true, checks EKU of server certificate. + public var checksEKU: Bool? + /// Sets compression framing, disabled by default. public var compressionFraming: CompressionFraming @@ -175,6 +178,7 @@ extension SessionProxy { self.ca = ca clientCertificate = nil clientKey = nil + checksEKU = false compressionFraming = .disabled tlsWrap = nil keepAliveInterval = nil @@ -195,6 +199,7 @@ extension SessionProxy { ca: ca, clientCertificate: clientCertificate, clientKey: clientKey, + checksEKU: checksEKU, compressionFraming: compressionFraming, tlsWrap: tlsWrap, keepAliveInterval: keepAliveInterval, @@ -223,6 +228,9 @@ extension SessionProxy { /// - Seealso: `SessionProxy.ConfigurationBuilder.clientKey` public let clientKey: CryptoContainer? + /// - Seealso: `SessionProxy.ConfigurationBuilder.checksEKU` + public let checksEKU: Bool? + /// - Seealso: `SessionProxy.ConfigurationBuilder.compressionFraming` public let compressionFraming: CompressionFraming @@ -252,6 +260,7 @@ extension SessionProxy { builder.digest = digest builder.clientCertificate = clientCertificate builder.clientKey = clientKey + builder.checksEKU = checksEKU builder.compressionFraming = compressionFraming builder.tlsWrap = tlsWrap builder.keepAliveInterval = keepAliveInterval @@ -271,6 +280,7 @@ extension SessionProxy { (lhs.ca == rhs.ca) && (lhs.clientCertificate == rhs.clientCertificate) && (lhs.clientKey == rhs.clientKey) && + (lhs.checksEKU == rhs.checksEKU) && (lhs.compressionFraming == rhs.compressionFraming) && (lhs.keepAliveInterval == rhs.keepAliveInterval) && (lhs.renegotiatesAfter == rhs.renegotiatesAfter) && diff --git a/TunnelKit/Sources/Core/SessionProxy.swift b/TunnelKit/Sources/Core/SessionProxy.swift index e045c68..3a45bf3 100644 --- a/TunnelKit/Sources/Core/SessionProxy.swift +++ b/TunnelKit/Sources/Core/SessionProxy.swift @@ -771,7 +771,8 @@ public class SessionProxy { negotiationKey.tlsOptional = TLSBox( caPath: caURL.path, clientCertificatePath: (configuration.clientCertificate != nil) ? clientCertificateURL.path : nil, - clientKeyPath: (configuration.clientKey != nil) ? clientKeyURL.path : nil + clientKeyPath: (configuration.clientKey != nil) ? clientKeyURL.path : nil, + checksEKU: true ) do { try negotiationKey.tls.start() diff --git a/TunnelKit/Sources/Core/TLSBox.h b/TunnelKit/Sources/Core/TLSBox.h index 76e6d54..16194f5 100644 --- a/TunnelKit/Sources/Core/TLSBox.h +++ b/TunnelKit/Sources/Core/TLSBox.h @@ -55,7 +55,8 @@ extern NSString *const TLSBoxPeerVerificationErrorNotification; - (instancetype)initWithCAPath:(NSString *)caPath clientCertificatePath:(nullable NSString *)clientCertificatePath - clientKeyPath:(nullable NSString *)clientKeyPath; + clientKeyPath:(nullable NSString *)clientKeyPath + checksEKU:(BOOL)checksEKU; - (BOOL)startWithError:(NSError **)error; diff --git a/TunnelKit/Sources/Core/TLSBox.m b/TunnelKit/Sources/Core/TLSBox.m index 65f9a78..6a7a532 100644 --- a/TunnelKit/Sources/Core/TLSBox.m +++ b/TunnelKit/Sources/Core/TLSBox.m @@ -65,6 +65,7 @@ int TLSBoxVerifyPeer(int ok, X509_STORE_CTX *ctx) { @property (nonatomic, strong) NSString *caPath; @property (nonatomic, strong) NSString *clientCertificatePath; @property (nonatomic, strong) NSString *clientKeyPath; +@property (nonatomic, assign) BOOL checksEKU; @property (nonatomic, assign) BOOL isConnected; @property (nonatomic, unsafe_unretained) SSL_CTX *ctx; @@ -105,12 +106,16 @@ int TLSBoxVerifyPeer(int ok, X509_STORE_CTX *ctx) { return nil; } -- (instancetype)initWithCAPath:(NSString *)caPath clientCertificatePath:(NSString *)clientCertificatePath clientKeyPath:(NSString *)clientKeyPath +- (instancetype)initWithCAPath:(NSString *)caPath + clientCertificatePath:(NSString *)clientCertificatePath + clientKeyPath:(NSString *)clientKeyPath + checksEKU:(BOOL)checksEKU { if ((self = [super init])) { self.caPath = caPath; self.clientCertificatePath = clientCertificatePath; self.clientKeyPath = clientKeyPath; + self.checksEKU = checksEKU; self.bufferCipherText = allocate_safely(TLSBoxMaxBufferLength); } return self; @@ -196,7 +201,7 @@ int TLSBoxVerifyPeer(int ok, X509_STORE_CTX *ctx) { if (!self.isConnected && SSL_is_init_finished(self.ssl)) { self.isConnected = YES; - if (![self verifyEKUWithSSL:self.ssl]) { + if (self.checksEKU && ![self verifyEKUWithSSL:self.ssl]) { if (error) { *error = TunnelKitErrorWithCode(TunnelKitErrorCodeTLSBoxServerEKU); } diff --git a/TunnelKitHost/Info.plist b/TunnelKitHost/Info.plist index cf71a3c..312dc08 100644 --- a/TunnelKitHost/Info.plist +++ b/TunnelKitHost/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.4.0 + 1.4.1 CFBundleVersion 1 LSRequiresIPhoneOS diff --git a/TunnelKitTests-iOS/Info.plist b/TunnelKitTests-iOS/Info.plist index 2e93959..9b7344f 100644 --- a/TunnelKitTests-iOS/Info.plist +++ b/TunnelKitTests-iOS/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.4.0 + 1.4.1 CFBundleVersion 1 diff --git a/TunnelKitTests-macOS/Info.plist b/TunnelKitTests-macOS/Info.plist index 2e93959..9b7344f 100644 --- a/TunnelKitTests-macOS/Info.plist +++ b/TunnelKitTests-macOS/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.4.0 + 1.4.1 CFBundleVersion 1