From 23beb936cfd2a1f87af5f3e4968df776e139a7d4 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 6 Sep 2017 18:07:16 +0300 Subject: [PATCH 01/42] Declare OpenVPNCertificate class and its methods for parsing PEM and DER format --- OpenVPN Adapter/OpenVPNCertificate.h | 21 +++++++++++ OpenVPN Adapter/OpenVPNCertificate.m | 54 ++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 OpenVPN Adapter/OpenVPNCertificate.h create mode 100644 OpenVPN Adapter/OpenVPNCertificate.m diff --git a/OpenVPN Adapter/OpenVPNCertificate.h b/OpenVPN Adapter/OpenVPNCertificate.h new file mode 100644 index 0000000..cc3677f --- /dev/null +++ b/OpenVPN Adapter/OpenVPNCertificate.h @@ -0,0 +1,21 @@ +// +// OpenVPNCertificate.h +// OpenVPN Adapter +// +// Created by Sergey Abramchuk on 06.09.17. +// +// + +#import + +@interface OpenVPNCertificate : NSObject + ++ (nullable OpenVPNCertificate *)certificateWithPEM:(nonnull NSData *)pemData + error:(out NSError * __nullable * __nullable)error; + ++ (nullable OpenVPNCertificate *)certificateWithDER:(nonnull NSData *)derData + error:(out NSError * __nullable * __nullable)error; + +- (nonnull instancetype) __unavailable init; + +@end diff --git a/OpenVPN Adapter/OpenVPNCertificate.m b/OpenVPN Adapter/OpenVPNCertificate.m new file mode 100644 index 0000000..fd09813 --- /dev/null +++ b/OpenVPN Adapter/OpenVPNCertificate.m @@ -0,0 +1,54 @@ +// +// OpenVPNCertificate.m +// OpenVPN Adapter +// +// Created by Sergey Abramchuk on 06.09.17. +// +// + +#import + +#import "OpenVPNCertificate.h" + +@interface OpenVPNCertificate () + +@property (nonatomic) mbedtls_x509_crt *crt; + +@end + +@implementation OpenVPNCertificate + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.crt = malloc(sizeof(mbedtls_x509_crt)); + mbedtls_x509_crt_init(self.crt); + } + return self; +} + ++ (OpenVPNCertificate *)certificateWithPEM:(NSData *)pemData error:(out NSError * __nullable * __nullable)error { + OpenVPNCertificate *certificate = [OpenVPNCertificate new]; + + // TODO: Parse PEM data + + return certificate; +} + ++ (OpenVPNCertificate *)certificateWithDER:(NSData *)derData error:(out NSError * __nullable * __nullable)error { + OpenVPNCertificate *certificate = [OpenVPNCertificate new]; + + // TODO: Parse DER data + + return certificate; +} + +- (void)dealloc { + if (self.crt) { + mbedtls_x509_crt_free(self.crt); + free(self.crt); + } +} + +@end From 002e6287f9fe5cfafbd86654862c46e00174d45f Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 6 Sep 2017 18:08:39 +0300 Subject: [PATCH 02/42] Add OpenVPNCertificate files and their tests to the project --- .../OpenVPNCertificateTests.swift | 43 +++++++++++++++++++ OpenVPN Adapter Tests/Resources/ca.crt | 17 ++++++++ OpenVPN Adapter Tests/Resources/ca.key | 15 +++++++ OpenVPN Adapter.xcodeproj/project.pbxproj | 38 ++++++++++++++++ 4 files changed, 113 insertions(+) create mode 100644 OpenVPN Adapter Tests/OpenVPNCertificateTests.swift create mode 100644 OpenVPN Adapter Tests/Resources/ca.crt create mode 100644 OpenVPN Adapter Tests/Resources/ca.key diff --git a/OpenVPN Adapter Tests/OpenVPNCertificateTests.swift b/OpenVPN Adapter Tests/OpenVPNCertificateTests.swift new file mode 100644 index 0000000..2b575f8 --- /dev/null +++ b/OpenVPN Adapter Tests/OpenVPNCertificateTests.swift @@ -0,0 +1,43 @@ +// +// OpenVPNCertificateTests.swift +// OpenVPN Adapter +// +// Created by Sergey Abramchuk on 06.09.17. +// +// + +import XCTest +@testable import OpenVPNAdapter + +class OpenVPNCertificateTests: XCTestCase { + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testCertificateFromPEM() { + guard + let caURL = Bundle.current.url(forResource: "ca", withExtension: "crt"), + let caData = try? Data(contentsOf: caURL) +// let caContent = try? String(contentsOf: caURL, encoding: .utf8).cString(using: .utf8) + else { + XCTFail("") + return + } + + let certificate: OpenVPNCertificate + do { + certificate = try OpenVPNCertificate(pem: caData) + } catch { + XCTFail(error.localizedDescription) + return + } + } + +} diff --git a/OpenVPN Adapter Tests/Resources/ca.crt b/OpenVPN Adapter Tests/Resources/ca.crt new file mode 100644 index 0000000..13916da --- /dev/null +++ b/OpenVPN Adapter Tests/Resources/ca.crt @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICvDCCAiWgAwIBAgIJAIk6JnSDG7spMA0GCSqGSIb3DQEBBQUAMEkxCzAJBgNV +BAYTAlJVMRMwEQYDVQQIEwpTb21lLVN0YXRlMRQwEgYDVQQHEwtBcmtoYW5nZWxz +azEPMA0GA1UEChMGUy1USUNLMB4XDTE3MDkwNjE0MDc1MVoXDTE3MTAwNjE0MDc1 +MVowSTELMAkGA1UEBhMCUlUxEzARBgNVBAgTClNvbWUtU3RhdGUxFDASBgNVBAcT +C0Fya2hhbmdlbHNrMQ8wDQYDVQQKEwZTLVRJQ0swgZ8wDQYJKoZIhvcNAQEBBQAD +gY0AMIGJAoGBAMXgr0CSQmXqzeYv3tqHDVeAnjt2eFlFya1RJIE59Vu3quAD/6Us +fM2VUAtjRu+Bh8QYefsJ5IBpT7AnaUi5TM0XDBW9iPxxXus2l0QtCiCf/JDEDk19 +Ig5e4lbJMwR/QuEw6LceVXmcxIYsZBnw4Ni7DcXbBeLKuEQuiUOMXcqrAgMBAAGj +gaswgagwHQYDVR0OBBYEFE4iwGwZysk3DA8xMI9lM1yljKtVMHkGA1UdIwRyMHCA +FE4iwGwZysk3DA8xMI9lM1yljKtVoU2kSzBJMQswCQYDVQQGEwJSVTETMBEGA1UE +CBMKU29tZS1TdGF0ZTEUMBIGA1UEBxMLQXJraGFuZ2Vsc2sxDzANBgNVBAoTBlMt +VElDS4IJAIk6JnSDG7spMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEA +iBlchqANsArwiY6xO3rpWsuvOQaijUY0DicHnzriEcrD3XATRKllQ6vekXHolsKl +1tq88AmNhn95s9zOgEGrFftvb06UwZ/zGiuXlUPTkiFxOP3rqXmYG9pn431DhMfm +rr2dVN0/94np8jELlpnxFiB79GWSPjVOfXDmZ266oD4= +-----END CERTIFICATE----- diff --git a/OpenVPN Adapter Tests/Resources/ca.key b/OpenVPN Adapter Tests/Resources/ca.key new file mode 100644 index 0000000..bff2359 --- /dev/null +++ b/OpenVPN Adapter Tests/Resources/ca.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDF4K9AkkJl6s3mL97ahw1XgJ47dnhZRcmtUSSBOfVbt6rgA/+l +LHzNlVALY0bvgYfEGHn7CeSAaU+wJ2lIuUzNFwwVvYj8cV7rNpdELQogn/yQxA5N +fSIOXuJWyTMEf0LhMOi3HlV5nMSGLGQZ8ODYuw3F2wXiyrhELolDjF3KqwIDAQAB +AoGAUPOBXr43EbDEeSYeWnIjoCeLFDJ8O7FUN2ZZs9A9Mz9pVWntXOpdSFGMRIxh +ybvJCg0lYfEDHRF4O010Qf8kjo5Y+KRUJgV7J3HG4O8XkpYBnNMJa1wJYBdreFe2 +iUgcEaBRK55LOOftiE34dLQMgJlaySuNBtfNlORlqJJ0Z6kCQQDpNgeEdytUbjx+ +aJhnxNtXy6yJ0EUKoDPi9xKpa3K7ZxB6tfA+B+WtgLKWfFSorK9P3cSH9B0Pr2OO +MGK2x2PPAkEA2TbC05eQ/XUqiH6yvbtss5Q73YabIj8g6hd6IyHW2b10Qt27CCZS +pEwB16XXtJqXCOcqY3spuORM/Y14f652ZQJAdjc6Jk7WOw1KQvW4U9m5Kk8HXjCh +3toIk0OVRSY/WXnMI7f4WSldps63OIs7yukGUSDkj9oRpTLN73TdhTObhwJBANbb +fhfCot6zWOEvQiq/DCUOCbF0hlt3yl0D4AKEZHt5FVlW7rx++9wceu4O07GIAMID +t0A0Ae8rlKRxnbHepqkCQD+XNnuUSi+zJB07Qmsx1ywQr9zH4lDVuZ660LELWYPr +rp8x07XiCFKvmGWDLuKsEBzj5eBwqlTUywwjhwYm8Xo= +-----END RSA PRIVATE KEY----- diff --git a/OpenVPN Adapter.xcodeproj/project.pbxproj b/OpenVPN Adapter.xcodeproj/project.pbxproj index c71f75d..365031e 100644 --- a/OpenVPN Adapter.xcodeproj/project.pbxproj +++ b/OpenVPN Adapter.xcodeproj/project.pbxproj @@ -104,6 +104,16 @@ C9BDB1361EBCC3B900C204FF /* OpenVPNTunnelSettings.h in Headers */ = {isa = PBXBuildFile; fileRef = C9BDB1331EBCC3B900C204FF /* OpenVPNTunnelSettings.h */; }; C9BDB1371EBCC3B900C204FF /* OpenVPNTunnelSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = C9BDB1341EBCC3B900C204FF /* OpenVPNTunnelSettings.m */; }; C9BDB1381EBCC3B900C204FF /* OpenVPNTunnelSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = C9BDB1341EBCC3B900C204FF /* OpenVPNTunnelSettings.m */; }; + C9CA4DD31F602F7B00C4F184 /* OpenVPNCertificate.h in Headers */ = {isa = PBXBuildFile; fileRef = C9CA4DD11F602F7B00C4F184 /* OpenVPNCertificate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C9CA4DD41F602F7B00C4F184 /* OpenVPNCertificate.h in Headers */ = {isa = PBXBuildFile; fileRef = C9CA4DD11F602F7B00C4F184 /* OpenVPNCertificate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C9CA4DD51F602F7B00C4F184 /* OpenVPNCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = C9CA4DD21F602F7B00C4F184 /* OpenVPNCertificate.m */; }; + C9CA4DD61F602F7B00C4F184 /* OpenVPNCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = C9CA4DD21F602F7B00C4F184 /* OpenVPNCertificate.m */; }; + C9CA4DD91F6038F000C4F184 /* ca.key in Resources */ = {isa = PBXBuildFile; fileRef = C9CA4DD71F6038F000C4F184 /* ca.key */; }; + C9CA4DDA1F6038F000C4F184 /* ca.key in Resources */ = {isa = PBXBuildFile; fileRef = C9CA4DD71F6038F000C4F184 /* ca.key */; }; + C9CA4DDB1F6038F000C4F184 /* ca.crt in Resources */ = {isa = PBXBuildFile; fileRef = C9CA4DD81F6038F000C4F184 /* ca.crt */; }; + C9CA4DDC1F6038F000C4F184 /* ca.crt in Resources */ = {isa = PBXBuildFile; fileRef = C9CA4DD81F6038F000C4F184 /* ca.crt */; }; + C9CA4DE11F603A5300C4F184 /* OpenVPNCertificateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9CA4DE01F603A5300C4F184 /* OpenVPNCertificateTests.swift */; }; + C9CA4DE21F603A5300C4F184 /* OpenVPNCertificateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9CA4DE01F603A5300C4F184 /* OpenVPNCertificateTests.swift */; }; C9D2ABDB1EA20F99007EDF9D /* OpenVPNAdapter.mm in Sources */ = {isa = PBXBuildFile; fileRef = C9BB477E1E7173C700F3F98C /* OpenVPNAdapter.mm */; }; C9D2ABDC1EA20F99007EDF9D /* OpenVPNClient.mm in Sources */ = {isa = PBXBuildFile; fileRef = C9BB47781E7171ED00F3F98C /* OpenVPNClient.mm */; }; C9D2ABDE1EA20F99007EDF9D /* ovpncli.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C9FD92191E9A667600374FC4 /* ovpncli.cpp */; }; @@ -206,6 +216,11 @@ C9BCE25C1EB3C201009D6AC1 /* OpenVPNSessionToken+Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OpenVPNSessionToken+Internal.h"; sourceTree = ""; }; C9BDB1331EBCC3B900C204FF /* OpenVPNTunnelSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenVPNTunnelSettings.h; sourceTree = ""; }; C9BDB1341EBCC3B900C204FF /* OpenVPNTunnelSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OpenVPNTunnelSettings.m; sourceTree = ""; }; + C9CA4DD11F602F7B00C4F184 /* OpenVPNCertificate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenVPNCertificate.h; sourceTree = ""; }; + C9CA4DD21F602F7B00C4F184 /* OpenVPNCertificate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OpenVPNCertificate.m; sourceTree = ""; }; + C9CA4DD71F6038F000C4F184 /* ca.key */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ca.key; sourceTree = ""; }; + C9CA4DD81F6038F000C4F184 /* ca.crt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ca.crt; sourceTree = ""; }; + C9CA4DE01F603A5300C4F184 /* OpenVPNCertificateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenVPNCertificateTests.swift; sourceTree = ""; }; C9D2ABF01EA20F99007EDF9D /* OpenVPNAdapter.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OpenVPNAdapter.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C9D2ABFF1EA212A3007EDF9D /* OpenVPNAdapterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OpenVPNAdapterTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; C9FD92181E9A667600374FC4 /* ovpncli.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ovpncli.hpp; path = Vendors/openvpn/client/ovpncli.hpp; sourceTree = ""; }; @@ -366,6 +381,7 @@ C9BB475D1E71663A00F3F98C /* OpenVPN Adapter */ = { isa = PBXGroup; children = ( + C9CA4DD01F602D8300C4F184 /* Certificates and Keys */, C9B7955B1F1D165700CF35FE /* Reachability */, C9235AC41EB24F0100C7D303 /* Configuration */, C9235AC51EB24F1100C7D303 /* Stats and Info */, @@ -436,6 +452,8 @@ C9BB479A1E71836100F3F98C /* Resources */ = { isa = PBXGroup; children = ( + C9CA4DD71F6038F000C4F184 /* ca.key */, + C9CA4DD81F6038F000C4F184 /* ca.crt */, C98467A11EAA559B00272A9A /* local_vpn_server.ovpn */, ); path = Resources; @@ -444,6 +462,7 @@ C9BB479D1E71837200F3F98C /* Adapter Tests */ = { isa = PBXGroup; children = ( + C9CA4DE01F603A5300C4F184 /* OpenVPNCertificateTests.swift */, C9354F431F1E49A500F4C935 /* OpenVPNReachabilityTests.swift */, C94605E81EAA656B00971516 /* OpenVPNConfigurationTests.swift */, C9BB47901E71821A00F3F98C /* OpenVPNAdapterTests.swift */, @@ -476,6 +495,15 @@ name = Utils; sourceTree = ""; }; + C9CA4DD01F602D8300C4F184 /* Certificates and Keys */ = { + isa = PBXGroup; + children = ( + C9CA4DD11F602F7B00C4F184 /* OpenVPNCertificate.h */, + C9CA4DD21F602F7B00C4F184 /* OpenVPNCertificate.m */, + ); + name = "Certificates and Keys"; + sourceTree = ""; + }; C9FF73B71EB7421600E995AC /* Helpers */ = { isa = PBXGroup; children = ( @@ -491,6 +519,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + C9CA4DD31F602F7B00C4F184 /* OpenVPNCertificate.h in Headers */, C9BB47791E7171ED00F3F98C /* OpenVPNClient.h in Headers */, C9657A3A1EB0BAAB00EFF210 /* OpenVPNInterfaceStats+Internal.h in Headers */, C9354F451F1E4A4500F4C935 /* OpenVPNReachabilityStatus.h in Headers */, @@ -532,6 +561,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + C9CA4DD41F602F7B00C4F184 /* OpenVPNCertificate.h in Headers */, C9D2ABE31EA20F99007EDF9D /* OpenVPNClient.h in Headers */, C9657A3B1EB0BAAB00EFF210 /* OpenVPNInterfaceStats+Internal.h in Headers */, C9354F461F1E4A4600F4C935 /* OpenVPNReachabilityStatus.h in Headers */, @@ -707,6 +737,8 @@ buildActionMask = 2147483647; files = ( C98467A21EAA559B00272A9A /* local_vpn_server.ovpn in Resources */, + C9CA4DDB1F6038F000C4F184 /* ca.crt in Resources */, + C9CA4DD91F6038F000C4F184 /* ca.key in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -722,6 +754,8 @@ buildActionMask = 2147483647; files = ( C98467A31EAA559B00272A9A /* local_vpn_server.ovpn in Resources */, + C9CA4DDC1F6038F000C4F184 /* ca.crt in Resources */, + C9CA4DDA1F6038F000C4F184 /* ca.key in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -771,6 +805,7 @@ C9657A311EB0B7A900EFF210 /* OpenVPNTransportStats.mm in Sources */, C9B795661F1D182500CF35FE /* OpenVPNReachabilityTracker.mm in Sources */, C9657A581EB0CE1300EFF210 /* OpenVPNProperties.mm in Sources */, + C9CA4DD51F602F7B00C4F184 /* OpenVPNCertificate.m in Sources */, C9BB477A1E7171ED00F3F98C /* OpenVPNClient.mm in Sources */, C9FD921B1E9A667600374FC4 /* ovpncli.cpp in Sources */, C9657A361EB0BA3900EFF210 /* OpenVPNInterfaceStats.mm in Sources */, @@ -788,6 +823,7 @@ C94605E91EAA656B00971516 /* OpenVPNConfigurationTests.swift in Sources */, C9BB47911E71821A00F3F98C /* OpenVPNAdapterTests.swift in Sources */, C9B03A7C1EABA82200268B85 /* ProfileLoader.swift in Sources */, + C9CA4DE11F603A5300C4F184 /* OpenVPNCertificateTests.swift in Sources */, C9BB47A21E7183DB00F3F98C /* Bundle.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -804,6 +840,7 @@ C9657A301EB0B7A600EFF210 /* OpenVPNTransportStats.mm in Sources */, C9B795671F1D182500CF35FE /* OpenVPNReachabilityTracker.mm in Sources */, C9657A591EB0CE1400EFF210 /* OpenVPNProperties.mm in Sources */, + C9CA4DD61F602F7B00C4F184 /* OpenVPNCertificate.m in Sources */, C9D2ABDC1EA20F99007EDF9D /* OpenVPNClient.mm in Sources */, C9D2ABDE1EA20F99007EDF9D /* ovpncli.cpp in Sources */, C9657A371EB0BA3900EFF210 /* OpenVPNInterfaceStats.mm in Sources */, @@ -820,6 +857,7 @@ files = ( C94605EA1EAA65F200971516 /* OpenVPNConfigurationTests.swift in Sources */, C9D2ABF61EA212A3007EDF9D /* OpenVPNAdapterTests.swift in Sources */, + C9CA4DE21F603A5300C4F184 /* OpenVPNCertificateTests.swift in Sources */, C9354F471F1E4AE200F4C935 /* OpenVPNReachabilityTests.swift in Sources */, C9B03A7D1EABA82300268B85 /* ProfileLoader.swift in Sources */, C9D2ABF71EA212A3007EDF9D /* Bundle.swift in Sources */, From 55524d4722826cc03ebc1d7a01d70f8fbf5c726b Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 6 Sep 2017 18:09:44 +0300 Subject: [PATCH 03/42] Add OpenVPNCertificate to the public headers --- OpenVPN Adapter/Umbrella-Header.h | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenVPN Adapter/Umbrella-Header.h b/OpenVPN Adapter/Umbrella-Header.h index 02c1192..6f82306 100644 --- a/OpenVPN Adapter/Umbrella-Header.h +++ b/OpenVPN Adapter/Umbrella-Header.h @@ -33,5 +33,6 @@ FOUNDATION_EXPORT const unsigned char OpenVPNAdapterVersionString[]; #import #import #import +#import #import #import From 062b07a9570685268d342cccbd11371921c778cb Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 6 Sep 2017 18:10:26 +0300 Subject: [PATCH 04/42] Implement parsing certificate PEM data --- OpenVPN Adapter/OpenVPNCertificate.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/OpenVPN Adapter/OpenVPNCertificate.m b/OpenVPN Adapter/OpenVPNCertificate.m index fd09813..aee5591 100644 --- a/OpenVPN Adapter/OpenVPNCertificate.m +++ b/OpenVPN Adapter/OpenVPNCertificate.m @@ -31,7 +31,12 @@ + (OpenVPNCertificate *)certificateWithPEM:(NSData *)pemData error:(out NSError * __nullable * __nullable)error { OpenVPNCertificate *certificate = [OpenVPNCertificate new]; - // TODO: Parse PEM data + NSString *pemString = [[NSString alloc] initWithData:pemData encoding:NSUTF8StringEncoding]; + + int result = mbedtls_x509_crt_parse(certificate.crt, (const unsigned char *)pemString.UTF8String, pemData.length + 1); + if (result != 0) { + return nil; + } return certificate; } From 5f1343f7f2e7f048cfda67da66b0a93b02285cf6 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 6 Sep 2017 18:18:36 +0300 Subject: [PATCH 05/42] Implement parsing certificate DER data --- OpenVPN Adapter/OpenVPNCertificate.m | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/OpenVPN Adapter/OpenVPNCertificate.m b/OpenVPN Adapter/OpenVPNCertificate.m index aee5591..05b3582 100644 --- a/OpenVPN Adapter/OpenVPNCertificate.m +++ b/OpenVPN Adapter/OpenVPNCertificate.m @@ -35,6 +35,10 @@ int result = mbedtls_x509_crt_parse(certificate.crt, (const unsigned char *)pemString.UTF8String, pemData.length + 1); if (result != 0) { + if (error) { + // TODO: Return parse error + } + return nil; } @@ -44,7 +48,14 @@ + (OpenVPNCertificate *)certificateWithDER:(NSData *)derData error:(out NSError * __nullable * __nullable)error { OpenVPNCertificate *certificate = [OpenVPNCertificate new]; - // TODO: Parse DER data + int result = mbedtls_x509_crt_parse_der(certificate.crt, derData.bytes, derData.length); + if (result != 0) { + if (error) { + // TODO: Return parse error + } + + return nil; + } return certificate; } From 760a5c7b749ef393607a75134c6d117d16609716 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 6 Sep 2017 19:04:03 +0300 Subject: [PATCH 06/42] Add assign modifier to the crt property --- OpenVPN Adapter/OpenVPNCertificate.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenVPN Adapter/OpenVPNCertificate.m b/OpenVPN Adapter/OpenVPNCertificate.m index 05b3582..bfa942c 100644 --- a/OpenVPN Adapter/OpenVPNCertificate.m +++ b/OpenVPN Adapter/OpenVPNCertificate.m @@ -12,7 +12,7 @@ @interface OpenVPNCertificate () -@property (nonatomic) mbedtls_x509_crt *crt; +@property (nonatomic, assign) mbedtls_x509_crt *crt; @end From 3c2040aacde975f210c9d7fd9d929f8761fa853f Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 6 Sep 2017 22:09:57 +0300 Subject: [PATCH 07/42] Add error domain for identities --- OpenVPN Adapter/OpenVPNError.h | 1 + OpenVPN Adapter/OpenVPNError.m | 1 + 2 files changed, 2 insertions(+) diff --git a/OpenVPN Adapter/OpenVPNError.h b/OpenVPN Adapter/OpenVPNError.h index d68a390..6e985d3 100644 --- a/OpenVPN Adapter/OpenVPNError.h +++ b/OpenVPN Adapter/OpenVPNError.h @@ -9,6 +9,7 @@ #import FOUNDATION_EXPORT NSString * __nonnull const OpenVPNAdapterErrorDomain; +FOUNDATION_EXPORT NSString * __nonnull const OpenVPNIdentityErrorDomain; FOUNDATION_EXPORT NSString * __nonnull const OpenVPNAdapterErrorFatalKey; FOUNDATION_EXPORT NSString * __nonnull const OpenVPNAdapterErrorMessageKey; diff --git a/OpenVPN Adapter/OpenVPNError.m b/OpenVPN Adapter/OpenVPNError.m index 9b85335..b7785b8 100644 --- a/OpenVPN Adapter/OpenVPNError.m +++ b/OpenVPN Adapter/OpenVPNError.m @@ -9,6 +9,7 @@ #import NSString * const OpenVPNAdapterErrorDomain = @"me.ss-abramchuk.openvpn-adapter.error-domain"; +NSString * const OpenVPNIdentityErrorDomain = @"me.ss-abramchuk.openvpn-identity.error-domain"; NSString * const OpenVPNAdapterErrorFatalKey = @"me.ss-abramchuk.openvpn-adapter.error-key.fatal"; NSString * const OpenVPNAdapterErrorMessageKey = @"me.ss-abramchuk.openvpn-adapter.error-key.message"; From 513da9cad40dd54bfee3959180a100a92019973c Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 6 Sep 2017 22:21:04 +0300 Subject: [PATCH 08/42] Add Utils group to the project --- OpenVPN Adapter.xcodeproj/project.pbxproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/OpenVPN Adapter.xcodeproj/project.pbxproj b/OpenVPN Adapter.xcodeproj/project.pbxproj index 365031e..2472913 100644 --- a/OpenVPN Adapter.xcodeproj/project.pbxproj +++ b/OpenVPN Adapter.xcodeproj/project.pbxproj @@ -504,10 +504,18 @@ name = "Certificates and Keys"; sourceTree = ""; }; + C9E4401A1F6081FF001D7C41 /* Utils */ = { + isa = PBXGroup; + children = ( + ); + name = Utils; + sourceTree = ""; + }; C9FF73B71EB7421600E995AC /* Helpers */ = { isa = PBXGroup; children = ( C9235AC61EB24F2A00C7D303 /* Types and Constants */, + C9E4401A1F6081FF001D7C41 /* Utils */, ); name = Helpers; sourceTree = ""; From 1d10acb6cfc689b3836a579c1b1a068324ef427b Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 6 Sep 2017 22:35:58 +0300 Subject: [PATCH 09/42] Remove unnecessary nullable keywords from method definitions --- OpenVPN Adapter/OpenVPNAdapter.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenVPN Adapter/OpenVPNAdapter.mm b/OpenVPN Adapter/OpenVPNAdapter.mm index 855edbd..b1b0fc7 100644 --- a/OpenVPN Adapter/OpenVPNAdapter.mm +++ b/OpenVPN Adapter/OpenVPNAdapter.mm @@ -434,7 +434,7 @@ static void socketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData #pragma mark Client Configuration -- (OpenVPNProperties *)applyConfiguration:(nonnull OpenVPNConfiguration *)configuration error:(out NSError * __nullable * __nullable)error { +- (OpenVPNProperties *)applyConfiguration:(nonnull OpenVPNConfiguration *)configuration error:(out NSError **)error { ClientAPI::EvalConfig eval = self.vpnClient->eval_config(configuration.config); if (eval.error) { NSString *errorReason = [self reasonForError:OpenVPNAdapterErrorConfigurationFailure]; @@ -451,7 +451,7 @@ static void socketCallback(CFSocketRef socket, CFSocketCallBackType type, CFData return [[OpenVPNProperties alloc] initWithEvalConfig:eval]; } -- (BOOL)provideCredentials:(nonnull OpenVPNCredentials *)credentials error:(out NSError * __nullable * __nullable)error { +- (BOOL)provideCredentials:(nonnull OpenVPNCredentials *)credentials error:(out NSError **)error { ClientAPI::Status status = self.vpnClient->provide_creds(credentials.credentials); if (status.error) { if (error) { From aa6eb81f97acb528db56b5e7117e5a61b4f6ee00 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 6 Sep 2017 22:57:35 +0300 Subject: [PATCH 10/42] Convert integer result to error reason --- OpenVPN Adapter/NSError+Message.h | 15 +++++++++++++++ OpenVPN Adapter/NSError+Message.m | 28 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 OpenVPN Adapter/NSError+Message.h create mode 100644 OpenVPN Adapter/NSError+Message.m diff --git a/OpenVPN Adapter/NSError+Message.h b/OpenVPN Adapter/NSError+Message.h new file mode 100644 index 0000000..6497c74 --- /dev/null +++ b/OpenVPN Adapter/NSError+Message.h @@ -0,0 +1,15 @@ +// +// NSError+Message.h +// OpenVPN Adapter +// +// Created by Sergey Abramchuk on 06.09.17. +// +// + +#import + +@interface NSError (Message) + ++ (NSString *)reasonFromResult:(NSInteger)result; + +@end diff --git a/OpenVPN Adapter/NSError+Message.m b/OpenVPN Adapter/NSError+Message.m new file mode 100644 index 0000000..47e3a66 --- /dev/null +++ b/OpenVPN Adapter/NSError+Message.m @@ -0,0 +1,28 @@ +// +// NSError+Message.m +// OpenVPN Adapter +// +// Created by Sergey Abramchuk on 06.09.17. +// +// + +#import + +#import "NSError+Message.h" + +@implementation NSError (Message) + ++ (NSString *)reasonFromResult:(NSInteger)result { + size_t length = 1024; + char *buffer = malloc(length); + + mbedtls_strerror(result, buffer, length); + + NSString *reason = [NSString stringWithUTF8String:buffer]; + + free(buffer); + + return reason; +} + +@end From 6c008afc59af79b538a2b2b905a439f4923238b1 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 6 Sep 2017 22:58:00 +0300 Subject: [PATCH 11/42] Add NSError+Message category to the project --- OpenVPN Adapter.xcodeproj/project.pbxproj | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/OpenVPN Adapter.xcodeproj/project.pbxproj b/OpenVPN Adapter.xcodeproj/project.pbxproj index 98df75c..d47273c 100644 --- a/OpenVPN Adapter.xcodeproj/project.pbxproj +++ b/OpenVPN Adapter.xcodeproj/project.pbxproj @@ -130,6 +130,10 @@ C9D2ABF61EA212A3007EDF9D /* OpenVPNAdapterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9BB47901E71821A00F3F98C /* OpenVPNAdapterTests.swift */; }; C9D2ABF71EA212A3007EDF9D /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9BB47A11E7183DB00F3F98C /* Bundle.swift */; }; C9D2AC051EA214EA007EDF9D /* OpenVPNAdapter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9D2ABF01EA20F99007EDF9D /* OpenVPNAdapter.framework */; }; + C9E4401D1F6086A1001D7C41 /* NSError+Message.h in Headers */ = {isa = PBXBuildFile; fileRef = C9E4401B1F6086A1001D7C41 /* NSError+Message.h */; }; + C9E4401E1F6086A1001D7C41 /* NSError+Message.h in Headers */ = {isa = PBXBuildFile; fileRef = C9E4401B1F6086A1001D7C41 /* NSError+Message.h */; }; + C9E4401F1F6086A1001D7C41 /* NSError+Message.m in Sources */ = {isa = PBXBuildFile; fileRef = C9E4401C1F6086A1001D7C41 /* NSError+Message.m */; }; + C9E440201F6086A1001D7C41 /* NSError+Message.m in Sources */ = {isa = PBXBuildFile; fileRef = C9E4401C1F6086A1001D7C41 /* NSError+Message.m */; }; C9FD921A1E9A667600374FC4 /* ovpncli.hpp in Headers */ = {isa = PBXBuildFile; fileRef = C9FD92181E9A667600374FC4 /* ovpncli.hpp */; }; C9FD921B1E9A667600374FC4 /* ovpncli.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C9FD92191E9A667600374FC4 /* ovpncli.cpp */; }; /* End PBXBuildFile section */ @@ -223,6 +227,8 @@ C9CA4DE01F603A5300C4F184 /* OpenVPNCertificateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenVPNCertificateTests.swift; sourceTree = ""; }; C9D2ABF01EA20F99007EDF9D /* OpenVPNAdapter.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OpenVPNAdapter.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C9D2ABFF1EA212A3007EDF9D /* OpenVPNAdapterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OpenVPNAdapterTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + C9E4401B1F6086A1001D7C41 /* NSError+Message.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+Message.h"; sourceTree = ""; }; + C9E4401C1F6086A1001D7C41 /* NSError+Message.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+Message.m"; sourceTree = ""; }; C9FD92181E9A667600374FC4 /* ovpncli.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ovpncli.hpp; path = Vendors/openvpn/client/ovpncli.hpp; sourceTree = ""; }; C9FD92191E9A667600374FC4 /* ovpncli.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ovpncli.cpp; path = Vendors/openvpn/client/ovpncli.cpp; sourceTree = ""; }; /* End PBXFileReference section */ @@ -507,6 +513,8 @@ C9E4401A1F6081FF001D7C41 /* Utils */ = { isa = PBXGroup; children = ( + C9E4401B1F6086A1001D7C41 /* NSError+Message.h */, + C9E4401C1F6086A1001D7C41 /* NSError+Message.m */, ); name = Utils; sourceTree = ""; @@ -553,6 +561,7 @@ C9BB47711E7171A100F3F98C /* OpenVPNError.h in Headers */, C9B795641F1D182500CF35FE /* OpenVPNReachabilityTracker.h in Headers */, C9BB47801E7173C700F3F98C /* OpenVPNAdapter+Internal.h in Headers */, + C9E4401D1F6086A1001D7C41 /* NSError+Message.h in Headers */, C9657A611EB0D64E00EFF210 /* OpenVPNIPv6Preference.h in Headers */, C9657A671EB0D73200EFF210 /* OpenVPNMinTLSVersion.h in Headers */, C93779D51EAE32670030A362 /* OpenVPNCredentials.h in Headers */, @@ -595,6 +604,7 @@ C9D2ABE81EA20F99007EDF9D /* OpenVPNError.h in Headers */, C9B795651F1D182500CF35FE /* OpenVPNReachabilityTracker.h in Headers */, C9D2ABE91EA20F99007EDF9D /* OpenVPNAdapter+Internal.h in Headers */, + C9E4401E1F6086A1001D7C41 /* NSError+Message.h in Headers */, C9657A621EB0D64E00EFF210 /* OpenVPNIPv6Preference.h in Headers */, C9657A681EB0D73200EFF210 /* OpenVPNMinTLSVersion.h in Headers */, C93779D61EAE32670030A362 /* OpenVPNCredentials.h in Headers */, @@ -809,6 +819,7 @@ C9BCE25A1EB3C0D9009D6AC1 /* OpenVPNSessionToken.mm in Sources */, C9BB47821E7173C700F3F98C /* OpenVPNAdapter.mm in Sources */, C98467A81EAA5B7700272A9A /* OpenVPNConfiguration.mm in Sources */, + C9E4401F1F6086A1001D7C41 /* NSError+Message.m in Sources */, C9BDB1371EBCC3B900C204FF /* OpenVPNTunnelSettings.m in Sources */, C9657A311EB0B7A900EFF210 /* OpenVPNTransportStats.mm in Sources */, C9B795661F1D182500CF35FE /* OpenVPNReachabilityTracker.mm in Sources */, @@ -844,6 +855,7 @@ C9BCE25B1EB3C0D9009D6AC1 /* OpenVPNSessionToken.mm in Sources */, C9D2ABDB1EA20F99007EDF9D /* OpenVPNAdapter.mm in Sources */, C98467A91EAA5B7700272A9A /* OpenVPNConfiguration.mm in Sources */, + C9E440201F6086A1001D7C41 /* NSError+Message.m in Sources */, C9BDB1381EBCC3B900C204FF /* OpenVPNTunnelSettings.m in Sources */, C9657A301EB0B7A600EFF210 /* OpenVPNTransportStats.mm in Sources */, C9B795671F1D182500CF35FE /* OpenVPNReachabilityTracker.mm in Sources */, From da4abe9ba139b73792902089c7d7d2aefccf0ebb Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 6 Sep 2017 22:58:41 +0300 Subject: [PATCH 12/42] Return error object if parsing finished with failure --- OpenVPN Adapter/OpenVPNCertificate.m | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/OpenVPN Adapter/OpenVPNCertificate.m b/OpenVPN Adapter/OpenVPNCertificate.m index bfa942c..49b6d9c 100644 --- a/OpenVPN Adapter/OpenVPNCertificate.m +++ b/OpenVPN Adapter/OpenVPNCertificate.m @@ -8,6 +8,8 @@ #import +#import "NSError+Message.h" +#import "OpenVPNError.h" #import "OpenVPNCertificate.h" @interface OpenVPNCertificate () @@ -34,9 +36,13 @@ NSString *pemString = [[NSString alloc] initWithData:pemData encoding:NSUTF8StringEncoding]; int result = mbedtls_x509_crt_parse(certificate.crt, (const unsigned char *)pemString.UTF8String, pemData.length + 1); - if (result != 0) { + if (result < 0) { if (error) { - // TODO: Return parse error + NSString *reason = [NSError reasonFromResult:result]; + *error = [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:result userInfo:@{ + NSLocalizedDescriptionKey: @"Failed to parse PEM data.", + NSLocalizedFailureReasonErrorKey: reason + }]; } return nil; @@ -49,9 +55,13 @@ OpenVPNCertificate *certificate = [OpenVPNCertificate new]; int result = mbedtls_x509_crt_parse_der(certificate.crt, derData.bytes, derData.length); - if (result != 0) { + if (result < 0) { if (error) { - // TODO: Return parse error + NSString *reason = [NSError reasonFromResult:result]; + *error = [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:result userInfo:@{ + NSLocalizedDescriptionKey: @"Failed to parse DER data.", + NSLocalizedFailureReasonErrorKey: reason + }]; } return nil; From 6c729008d7c0b0c97d7abc0fafb688b637d97e77 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 6 Sep 2017 22:59:31 +0300 Subject: [PATCH 13/42] Test parsing PEM data with incorrect value --- OpenVPN Adapter Tests/OpenVPNCertificateTests.swift | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/OpenVPN Adapter Tests/OpenVPNCertificateTests.swift b/OpenVPN Adapter Tests/OpenVPNCertificateTests.swift index 2b575f8..dd83b13 100644 --- a/OpenVPN Adapter Tests/OpenVPNCertificateTests.swift +++ b/OpenVPN Adapter Tests/OpenVPNCertificateTests.swift @@ -39,5 +39,18 @@ class OpenVPNCertificateTests: XCTestCase { return } } + + func testCertificateFromEmptyPEM() { + let caData = Data(count: 1024) + + let certificate: OpenVPNCertificate + do { + certificate = try OpenVPNCertificate(pem: caData) + } catch { + return + } + + XCTFail("Initialization with empty PEM data should fail") + } } From f22702d2f60f2dce296b0ad77b35826fcbe5f059 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 6 Sep 2017 23:02:22 +0300 Subject: [PATCH 14/42] Remove unnecessary nullable keywords from method definitions --- OpenVPN Adapter/OpenVPNCertificate.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenVPN Adapter/OpenVPNCertificate.m b/OpenVPN Adapter/OpenVPNCertificate.m index 49b6d9c..c23ccf4 100644 --- a/OpenVPN Adapter/OpenVPNCertificate.m +++ b/OpenVPN Adapter/OpenVPNCertificate.m @@ -30,7 +30,7 @@ return self; } -+ (OpenVPNCertificate *)certificateWithPEM:(NSData *)pemData error:(out NSError * __nullable * __nullable)error { ++ (OpenVPNCertificate *)certificateWithPEM:(NSData *)pemData error:(out NSError **)error { OpenVPNCertificate *certificate = [OpenVPNCertificate new]; NSString *pemString = [[NSString alloc] initWithData:pemData encoding:NSUTF8StringEncoding]; @@ -51,7 +51,7 @@ return certificate; } -+ (OpenVPNCertificate *)certificateWithDER:(NSData *)derData error:(out NSError * __nullable * __nullable)error { ++ (OpenVPNCertificate *)certificateWithDER:(NSData *)derData error:(out NSError **)error { OpenVPNCertificate *certificate = [OpenVPNCertificate new]; int result = mbedtls_x509_crt_parse_der(certificate.crt, derData.bytes, derData.length); From 18a41d88d188fa8e15cd74cd8b77ccc67973e5e3 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 6 Sep 2017 23:05:15 +0300 Subject: [PATCH 15/42] Remove a condition from the deallocation --- OpenVPN Adapter/OpenVPNCertificate.m | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/OpenVPN Adapter/OpenVPNCertificate.m b/OpenVPN Adapter/OpenVPNCertificate.m index c23ccf4..df8e3f2 100644 --- a/OpenVPN Adapter/OpenVPNCertificate.m +++ b/OpenVPN Adapter/OpenVPNCertificate.m @@ -71,10 +71,8 @@ } - (void)dealloc { - if (self.crt) { - mbedtls_x509_crt_free(self.crt); - free(self.crt); - } + mbedtls_x509_crt_free(self.crt); + free(self.crt); } @end From 7cbb69fed597a72bce51c0b60d38c23f81e079b0 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 6 Sep 2017 23:29:06 +0300 Subject: [PATCH 16/42] Implement writing certificate PEM data --- OpenVPN Adapter/OpenVPNCertificate.h | 2 ++ OpenVPN Adapter/OpenVPNCertificate.m | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/OpenVPN Adapter/OpenVPNCertificate.h b/OpenVPN Adapter/OpenVPNCertificate.h index cc3677f..bcc2464 100644 --- a/OpenVPN Adapter/OpenVPNCertificate.h +++ b/OpenVPN Adapter/OpenVPNCertificate.h @@ -18,4 +18,6 @@ - (nonnull instancetype) __unavailable init; +- (nullable NSData *)pemData:(out NSError * __nullable * __nullable)error; + @end diff --git a/OpenVPN Adapter/OpenVPNCertificate.m b/OpenVPN Adapter/OpenVPNCertificate.m index df8e3f2..0b1e839 100644 --- a/OpenVPN Adapter/OpenVPNCertificate.m +++ b/OpenVPN Adapter/OpenVPNCertificate.m @@ -7,6 +7,7 @@ // #import +#import #import "NSError+Message.h" #import "OpenVPNError.h" @@ -70,6 +71,31 @@ return certificate; } +- (NSData *)pemData:(out NSError **)error { + NSString *header = @"-----BEGIN CERTIFICATE-----\n"; + NSString *footer = @"-----END CERTIFICATE-----\n"; + + size_t buffer_length = self.crt->raw.len * 2; + unsigned char *pem_buffer = malloc(buffer_length); + + size_t output_length = 0; + + int result = mbedtls_pem_write_buffer(header.UTF8String, footer.UTF8String, self.crt->raw.p, self.crt->raw.len, pem_buffer, buffer_length, &output_length); + if (result < 0) { + if (error) { + NSString *reason = [NSError reasonFromResult:result]; + *error = [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:result userInfo:@{ + NSLocalizedDescriptionKey: @"Failed to write PEM data.", + NSLocalizedFailureReasonErrorKey: reason + }]; + } + + return nil; + } + + return [NSData dataWithBytes:pem_buffer length:output_length]; +} + - (void)dealloc { mbedtls_x509_crt_free(self.crt); free(self.crt); From d5a96bf7641958734ca1944db8791cd15e0d04aa Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 6 Sep 2017 23:31:25 +0300 Subject: [PATCH 17/42] Modify localized descriptions --- OpenVPN Adapter/OpenVPNCertificate.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenVPN Adapter/OpenVPNCertificate.m b/OpenVPN Adapter/OpenVPNCertificate.m index 0b1e839..43afb21 100644 --- a/OpenVPN Adapter/OpenVPNCertificate.m +++ b/OpenVPN Adapter/OpenVPNCertificate.m @@ -41,7 +41,7 @@ if (error) { NSString *reason = [NSError reasonFromResult:result]; *error = [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:result userInfo:@{ - NSLocalizedDescriptionKey: @"Failed to parse PEM data.", + NSLocalizedDescriptionKey: @"Failed to read PEM data.", NSLocalizedFailureReasonErrorKey: reason }]; } @@ -60,7 +60,7 @@ if (error) { NSString *reason = [NSError reasonFromResult:result]; *error = [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:result userInfo:@{ - NSLocalizedDescriptionKey: @"Failed to parse DER data.", + NSLocalizedDescriptionKey: @"Failed to read DER data.", NSLocalizedFailureReasonErrorKey: reason }]; } From b714cf11a1bd951f200276b49d7114d92d907854 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 10:21:10 +0300 Subject: [PATCH 18/42] Implement writing certificate DER data --- OpenVPN Adapter/OpenVPNCertificate.h | 1 + OpenVPN Adapter/OpenVPNCertificate.m | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/OpenVPN Adapter/OpenVPNCertificate.h b/OpenVPN Adapter/OpenVPNCertificate.h index bcc2464..4cbb7bd 100644 --- a/OpenVPN Adapter/OpenVPNCertificate.h +++ b/OpenVPN Adapter/OpenVPNCertificate.h @@ -19,5 +19,6 @@ - (nonnull instancetype) __unavailable init; - (nullable NSData *)pemData:(out NSError * __nullable * __nullable)error; +- (nullable NSData *)derData:(out NSError * __nullable * __nullable)error; @end diff --git a/OpenVPN Adapter/OpenVPNCertificate.m b/OpenVPN Adapter/OpenVPNCertificate.m index 43afb21..dc36e05 100644 --- a/OpenVPN Adapter/OpenVPNCertificate.m +++ b/OpenVPN Adapter/OpenVPNCertificate.m @@ -96,6 +96,19 @@ return [NSData dataWithBytes:pem_buffer length:output_length]; } +- (NSData *)derData:(out NSError **)error { + if (self.crt->raw.p == NULL || self.crt->raw.len == 0) { + *error = [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:MBEDTLS_ERR_X509_BAD_INPUT_DATA userInfo:@{ + NSLocalizedDescriptionKey: @"Failed to write DER data.", + NSLocalizedFailureReasonErrorKey: @"Input invalid" + }]; + + return nil; + } + + return [NSData dataWithBytes:self.crt->raw.p length:self.crt->raw.len]; +} + - (void)dealloc { mbedtls_x509_crt_free(self.crt); free(self.crt); From 066d6704f2ec11954c10bf7296e9aac2e72e941d Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 10:35:02 +0300 Subject: [PATCH 19/42] Use predefined result value for error reason --- OpenVPN Adapter/OpenVPNCertificate.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenVPN Adapter/OpenVPNCertificate.m b/OpenVPN Adapter/OpenVPNCertificate.m index dc36e05..c1f32ef 100644 --- a/OpenVPN Adapter/OpenVPNCertificate.m +++ b/OpenVPN Adapter/OpenVPNCertificate.m @@ -98,9 +98,10 @@ - (NSData *)derData:(out NSError **)error { if (self.crt->raw.p == NULL || self.crt->raw.len == 0) { + NSString *reason = [NSError reasonFromResult:MBEDTLS_ERR_X509_BAD_INPUT_DATA]; *error = [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:MBEDTLS_ERR_X509_BAD_INPUT_DATA userInfo:@{ NSLocalizedDescriptionKey: @"Failed to write DER data.", - NSLocalizedFailureReasonErrorKey: @"Input invalid" + NSLocalizedFailureReasonErrorKey:reason }]; return nil; From e4d57245ad76fda1c29c1b59bad0bf104c17cf9a Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 10:35:57 +0300 Subject: [PATCH 20/42] Remove null character --- OpenVPN Adapter/OpenVPNCertificate.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenVPN Adapter/OpenVPNCertificate.m b/OpenVPN Adapter/OpenVPNCertificate.m index c1f32ef..8789417 100644 --- a/OpenVPN Adapter/OpenVPNCertificate.m +++ b/OpenVPN Adapter/OpenVPNCertificate.m @@ -93,7 +93,7 @@ return nil; } - return [NSData dataWithBytes:pem_buffer length:output_length]; + return [NSData dataWithBytes:pem_buffer length:output_length - 1]; } - (NSData *)derData:(out NSError **)error { From b3ecfa1680b3760b8a280ed754d5b07034c7f6d5 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 10:51:57 +0300 Subject: [PATCH 21/42] Add boilerplate for OpenVPNPrivateKey implementation --- OpenVPN Adapter/OpenVPNPrivateKey.h | 26 +++++++++++++++ OpenVPN Adapter/OpenVPNPrivateKey.m | 49 +++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 OpenVPN Adapter/OpenVPNPrivateKey.h create mode 100644 OpenVPN Adapter/OpenVPNPrivateKey.m diff --git a/OpenVPN Adapter/OpenVPNPrivateKey.h b/OpenVPN Adapter/OpenVPNPrivateKey.h new file mode 100644 index 0000000..9157862 --- /dev/null +++ b/OpenVPN Adapter/OpenVPNPrivateKey.h @@ -0,0 +1,26 @@ +// +// OpenVPNPrivateKey.h +// OpenVPN Adapter +// +// Created by Sergey Abramchuk on 07.09.17. +// +// + +#import + +@interface OpenVPNPrivateKey : NSObject + ++ (nullable OpenVPNPrivateKey *)keyWithPEM:(nonnull NSData *)pemData + password:(nullable NSString *)password + error:(out NSError * __nullable * __nullable)error; + ++ (nullable OpenVPNPrivateKey *)keyWithDER:(nonnull NSData *)derData + password:(nullable NSString *)password + error:(out NSError * __nullable * __nullable)error; + +- (nonnull instancetype) __unavailable init; + +- (nullable NSData *)pemData:(out NSError * __nullable * __nullable)error; +- (nullable NSData *)derData:(out NSError * __nullable * __nullable)error; + +@end diff --git a/OpenVPN Adapter/OpenVPNPrivateKey.m b/OpenVPN Adapter/OpenVPNPrivateKey.m new file mode 100644 index 0000000..924b425 --- /dev/null +++ b/OpenVPN Adapter/OpenVPNPrivateKey.m @@ -0,0 +1,49 @@ +// +// OpenVPNPrivateKey.m +// OpenVPN Adapter +// +// Created by Sergey Abramchuk on 07.09.17. +// +// + +#import + +#import "NSError+Message.h" +#import "OpenVPNError.h" +#import "OpenVPNPrivateKey.h" + +@interface OpenVPNPrivateKey () + +@property (nonatomic, assign) mbedtls_pk_context *key; + +@end + +@implementation OpenVPNPrivateKey + +- (instancetype)init { + self = [super init]; + if (self) { + self.key = malloc(sizeof(mbedtls_pk_context)); + mbedtls_pk_init(self.key); + } + return self; +} + ++ (nullable OpenVPNPrivateKey *)keyWithPEM:(NSData *)pemData password:(NSString *)password error:(out NSError **)error { + OpenVPNPrivateKey *key = [OpenVPNPrivateKey new]; + + return key; +} + ++ (nullable OpenVPNPrivateKey *)keyWithDER:(NSData *)derData password:(NSString *)password error:(out NSError **)error { + OpenVPNPrivateKey *key = [OpenVPNPrivateKey new]; + + return key; +} + +- (void)dealloc { + mbedtls_pk_free(self.key); + free(self.key); +} + +@end From 2e289ec88cffe43527979b532958715cafdd7047 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 10:52:22 +0300 Subject: [PATCH 22/42] Add OpenVPNPrivateKey files to the project --- OpenVPN Adapter.xcodeproj/project.pbxproj | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/OpenVPN Adapter.xcodeproj/project.pbxproj b/OpenVPN Adapter.xcodeproj/project.pbxproj index d47273c..fa95b36 100644 --- a/OpenVPN Adapter.xcodeproj/project.pbxproj +++ b/OpenVPN Adapter.xcodeproj/project.pbxproj @@ -9,6 +9,10 @@ /* Begin PBXBuildFile section */ C90BAD311E73FF6C00DEFB32 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C90BAD301E73FF6C00DEFB32 /* SystemConfiguration.framework */; }; C912BB251E7C3339002B9414 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C912BB241E7C3339002B9414 /* NetworkExtension.framework */; }; + C915F1F41F612F3300B3DF23 /* OpenVPNPrivateKey.h in Headers */ = {isa = PBXBuildFile; fileRef = C915F1F21F612F3300B3DF23 /* OpenVPNPrivateKey.h */; }; + C915F1F51F612F3300B3DF23 /* OpenVPNPrivateKey.h in Headers */ = {isa = PBXBuildFile; fileRef = C915F1F21F612F3300B3DF23 /* OpenVPNPrivateKey.h */; }; + C915F1F61F612F3300B3DF23 /* OpenVPNPrivateKey.m in Sources */ = {isa = PBXBuildFile; fileRef = C915F1F31F612F3300B3DF23 /* OpenVPNPrivateKey.m */; }; + C915F1F71F612F3300B3DF23 /* OpenVPNPrivateKey.m in Sources */ = {isa = PBXBuildFile; fileRef = C915F1F31F612F3300B3DF23 /* OpenVPNPrivateKey.m */; }; C9354F451F1E4A4500F4C935 /* OpenVPNReachabilityStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = C9B795681F1D219C00CF35FE /* OpenVPNReachabilityStatus.h */; settings = {ATTRIBUTES = (Public, ); }; }; C9354F461F1E4A4600F4C935 /* OpenVPNReachabilityStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = C9B795681F1D219C00CF35FE /* OpenVPNReachabilityStatus.h */; settings = {ATTRIBUTES = (Public, ); }; }; C9354F471F1E4AE200F4C935 /* OpenVPNReachabilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9354F431F1E49A500F4C935 /* OpenVPNReachabilityTests.swift */; }; @@ -165,6 +169,8 @@ C90BAD2F1E73FA7400DEFB32 /* Tests.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Tests.xcconfig; sourceTree = ""; }; C90BAD301E73FF6C00DEFB32 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; C912BB241E7C3339002B9414 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; }; + C915F1F21F612F3300B3DF23 /* OpenVPNPrivateKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenVPNPrivateKey.h; sourceTree = ""; }; + C915F1F31F612F3300B3DF23 /* OpenVPNPrivateKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OpenVPNPrivateKey.m; sourceTree = ""; }; C9354F431F1E49A500F4C935 /* OpenVPNReachabilityTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenVPNReachabilityTests.swift; sourceTree = ""; }; C93779D31EAE32670030A362 /* OpenVPNCredentials.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenVPNCredentials.h; sourceTree = ""; }; C93779D41EAE32670030A362 /* OpenVPNCredentials.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = OpenVPNCredentials.mm; sourceTree = ""; }; @@ -506,6 +512,8 @@ children = ( C9CA4DD11F602F7B00C4F184 /* OpenVPNCertificate.h */, C9CA4DD21F602F7B00C4F184 /* OpenVPNCertificate.m */, + C915F1F21F612F3300B3DF23 /* OpenVPNPrivateKey.h */, + C915F1F31F612F3300B3DF23 /* OpenVPNPrivateKey.m */, ); name = "Certificates and Keys"; sourceTree = ""; @@ -556,6 +564,7 @@ C9657A5E1EB0D60700EFF210 /* OpenVPNTransportProtocol.h in Headers */, C9657A1D1EB0A8D800EFF210 /* OpenVPNConnectionInfo+Internal.h in Headers */, C9B7955E1F1D16AA00CF35FE /* OpenVPNReachability.h in Headers */, + C915F1F41F612F3300B3DF23 /* OpenVPNPrivateKey.h in Headers */, C9657A171EB0A7F800EFF210 /* OpenVPNConnectionInfo.h in Headers */, C9BB47811E7173C700F3F98C /* OpenVPNAdapter+Public.h in Headers */, C9BB47711E7171A100F3F98C /* OpenVPNError.h in Headers */, @@ -599,6 +608,7 @@ C9657A5F1EB0D60700EFF210 /* OpenVPNTransportProtocol.h in Headers */, C9657A1E1EB0A8D800EFF210 /* OpenVPNConnectionInfo+Internal.h in Headers */, C9B7955F1F1D16AA00CF35FE /* OpenVPNReachability.h in Headers */, + C915F1F51F612F3300B3DF23 /* OpenVPNPrivateKey.h in Headers */, C9657A181EB0A7F800EFF210 /* OpenVPNConnectionInfo.h in Headers */, C9D2ABE71EA20F99007EDF9D /* OpenVPNAdapter+Public.h in Headers */, C9D2ABE81EA20F99007EDF9D /* OpenVPNError.h in Headers */, @@ -825,6 +835,7 @@ C9B795661F1D182500CF35FE /* OpenVPNReachabilityTracker.mm in Sources */, C9657A581EB0CE1300EFF210 /* OpenVPNProperties.mm in Sources */, C9CA4DD51F602F7B00C4F184 /* OpenVPNCertificate.m in Sources */, + C915F1F61F612F3300B3DF23 /* OpenVPNPrivateKey.m in Sources */, C9BB477A1E7171ED00F3F98C /* OpenVPNClient.mm in Sources */, C9FD921B1E9A667600374FC4 /* ovpncli.cpp in Sources */, C9657A361EB0BA3900EFF210 /* OpenVPNInterfaceStats.mm in Sources */, @@ -861,6 +872,7 @@ C9B795671F1D182500CF35FE /* OpenVPNReachabilityTracker.mm in Sources */, C9657A591EB0CE1400EFF210 /* OpenVPNProperties.mm in Sources */, C9CA4DD61F602F7B00C4F184 /* OpenVPNCertificate.m in Sources */, + C915F1F71F612F3300B3DF23 /* OpenVPNPrivateKey.m in Sources */, C9D2ABDC1EA20F99007EDF9D /* OpenVPNClient.mm in Sources */, C9D2ABDE1EA20F99007EDF9D /* ovpncli.cpp in Sources */, C9657A371EB0BA3900EFF210 /* OpenVPNInterfaceStats.mm in Sources */, From 682831ba87054e2658c6a428483b3ce6dcd31ebd Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 10:53:35 +0300 Subject: [PATCH 23/42] Test converting PEM certificate data to DER and vice versa --- .../OpenVPNCertificateTests.swift | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/OpenVPN Adapter Tests/OpenVPNCertificateTests.swift b/OpenVPN Adapter Tests/OpenVPNCertificateTests.swift index dd83b13..8fb1016 100644 --- a/OpenVPN Adapter Tests/OpenVPNCertificateTests.swift +++ b/OpenVPN Adapter Tests/OpenVPNCertificateTests.swift @@ -21,23 +21,48 @@ class OpenVPNCertificateTests: XCTestCase { super.tearDown() } - func testCertificateFromPEM() { + func testCertificatePEMandDER() { guard let caURL = Bundle.current.url(forResource: "ca", withExtension: "crt"), - let caData = try? Data(contentsOf: caURL) -// let caContent = try? String(contentsOf: caURL, encoding: .utf8).cString(using: .utf8) + let caOriginalPEMData = try? Data(contentsOf: caURL) else { - XCTFail("") + XCTFail() return } - let certificate: OpenVPNCertificate + let certificateFromPEM: OpenVPNCertificate do { - certificate = try OpenVPNCertificate(pem: caData) + certificateFromPEM = try OpenVPNCertificate(pem: caOriginalPEMData) } catch { XCTFail(error.localizedDescription) return } + + let caDERData: Data + do { + caDERData = try certificateFromPEM.derData() + } catch { + XCTFail(error.localizedDescription) + return + } + + let certificateFromDER: OpenVPNCertificate + do { + certificateFromDER = try OpenVPNCertificate(der: caDERData) + } catch { + XCTFail(error.localizedDescription) + return + } + + let caGeneratedPEMData: Data + do { + caGeneratedPEMData = try certificateFromDER.pemData() + } catch { + XCTFail(error.localizedDescription) + return + } + + XCTAssert(caGeneratedPEMData.elementsEqual(caOriginalPEMData)) } func testCertificateFromEmptyPEM() { From 6fcb0f6da3541e4550873f9a7de74027b7eec39a Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 13:49:58 +0300 Subject: [PATCH 24/42] Add OpenVPNPrivateKeyTests to the project --- OpenVPN Adapter.xcodeproj/project.pbxproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OpenVPN Adapter.xcodeproj/project.pbxproj b/OpenVPN Adapter.xcodeproj/project.pbxproj index fa95b36..d24be65 100644 --- a/OpenVPN Adapter.xcodeproj/project.pbxproj +++ b/OpenVPN Adapter.xcodeproj/project.pbxproj @@ -13,6 +13,8 @@ C915F1F51F612F3300B3DF23 /* OpenVPNPrivateKey.h in Headers */ = {isa = PBXBuildFile; fileRef = C915F1F21F612F3300B3DF23 /* OpenVPNPrivateKey.h */; }; C915F1F61F612F3300B3DF23 /* OpenVPNPrivateKey.m in Sources */ = {isa = PBXBuildFile; fileRef = C915F1F31F612F3300B3DF23 /* OpenVPNPrivateKey.m */; }; C915F1F71F612F3300B3DF23 /* OpenVPNPrivateKey.m in Sources */ = {isa = PBXBuildFile; fileRef = C915F1F31F612F3300B3DF23 /* OpenVPNPrivateKey.m */; }; + C915F1F91F615BB400B3DF23 /* OpenVPNPrivateKeyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C915F1F81F615BB400B3DF23 /* OpenVPNPrivateKeyTests.swift */; }; + C915F1FA1F615BB400B3DF23 /* OpenVPNPrivateKeyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C915F1F81F615BB400B3DF23 /* OpenVPNPrivateKeyTests.swift */; }; C9354F451F1E4A4500F4C935 /* OpenVPNReachabilityStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = C9B795681F1D219C00CF35FE /* OpenVPNReachabilityStatus.h */; settings = {ATTRIBUTES = (Public, ); }; }; C9354F461F1E4A4600F4C935 /* OpenVPNReachabilityStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = C9B795681F1D219C00CF35FE /* OpenVPNReachabilityStatus.h */; settings = {ATTRIBUTES = (Public, ); }; }; C9354F471F1E4AE200F4C935 /* OpenVPNReachabilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9354F431F1E49A500F4C935 /* OpenVPNReachabilityTests.swift */; }; @@ -171,6 +173,7 @@ C912BB241E7C3339002B9414 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; }; C915F1F21F612F3300B3DF23 /* OpenVPNPrivateKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenVPNPrivateKey.h; sourceTree = ""; }; C915F1F31F612F3300B3DF23 /* OpenVPNPrivateKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OpenVPNPrivateKey.m; sourceTree = ""; }; + C915F1F81F615BB400B3DF23 /* OpenVPNPrivateKeyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenVPNPrivateKeyTests.swift; sourceTree = ""; }; C9354F431F1E49A500F4C935 /* OpenVPNReachabilityTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenVPNReachabilityTests.swift; sourceTree = ""; }; C93779D31EAE32670030A362 /* OpenVPNCredentials.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenVPNCredentials.h; sourceTree = ""; }; C93779D41EAE32670030A362 /* OpenVPNCredentials.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = OpenVPNCredentials.mm; sourceTree = ""; }; @@ -475,6 +478,7 @@ isa = PBXGroup; children = ( C9CA4DE01F603A5300C4F184 /* OpenVPNCertificateTests.swift */, + C915F1F81F615BB400B3DF23 /* OpenVPNPrivateKeyTests.swift */, C9354F431F1E49A500F4C935 /* OpenVPNReachabilityTests.swift */, C94605E81EAA656B00971516 /* OpenVPNConfigurationTests.swift */, C9BB47901E71821A00F3F98C /* OpenVPNAdapterTests.swift */, @@ -852,6 +856,7 @@ files = ( C94605E91EAA656B00971516 /* OpenVPNConfigurationTests.swift in Sources */, C9BB47911E71821A00F3F98C /* OpenVPNAdapterTests.swift in Sources */, + C915F1F91F615BB400B3DF23 /* OpenVPNPrivateKeyTests.swift in Sources */, C9B03A7C1EABA82200268B85 /* ProfileLoader.swift in Sources */, C9CA4DE11F603A5300C4F184 /* OpenVPNCertificateTests.swift in Sources */, C9BB47A21E7183DB00F3F98C /* Bundle.swift in Sources */, @@ -891,6 +896,7 @@ C9D2ABF61EA212A3007EDF9D /* OpenVPNAdapterTests.swift in Sources */, C9CA4DE21F603A5300C4F184 /* OpenVPNCertificateTests.swift in Sources */, C9354F471F1E4AE200F4C935 /* OpenVPNReachabilityTests.swift in Sources */, + C915F1FA1F615BB400B3DF23 /* OpenVPNPrivateKeyTests.swift in Sources */, C9B03A7D1EABA82300268B85 /* ProfileLoader.swift in Sources */, C9D2ABF71EA212A3007EDF9D /* Bundle.swift in Sources */, ); From 388b8231d74900f32386e7861b5ef2e6df5c4c7c Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 13:56:22 +0300 Subject: [PATCH 25/42] Set OpenVPNPrivateKey.h as public header --- OpenVPN Adapter.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenVPN Adapter.xcodeproj/project.pbxproj b/OpenVPN Adapter.xcodeproj/project.pbxproj index d24be65..3b8a3d4 100644 --- a/OpenVPN Adapter.xcodeproj/project.pbxproj +++ b/OpenVPN Adapter.xcodeproj/project.pbxproj @@ -9,8 +9,8 @@ /* Begin PBXBuildFile section */ C90BAD311E73FF6C00DEFB32 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C90BAD301E73FF6C00DEFB32 /* SystemConfiguration.framework */; }; C912BB251E7C3339002B9414 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C912BB241E7C3339002B9414 /* NetworkExtension.framework */; }; - C915F1F41F612F3300B3DF23 /* OpenVPNPrivateKey.h in Headers */ = {isa = PBXBuildFile; fileRef = C915F1F21F612F3300B3DF23 /* OpenVPNPrivateKey.h */; }; - C915F1F51F612F3300B3DF23 /* OpenVPNPrivateKey.h in Headers */ = {isa = PBXBuildFile; fileRef = C915F1F21F612F3300B3DF23 /* OpenVPNPrivateKey.h */; }; + C915F1F41F612F3300B3DF23 /* OpenVPNPrivateKey.h in Headers */ = {isa = PBXBuildFile; fileRef = C915F1F21F612F3300B3DF23 /* OpenVPNPrivateKey.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C915F1F51F612F3300B3DF23 /* OpenVPNPrivateKey.h in Headers */ = {isa = PBXBuildFile; fileRef = C915F1F21F612F3300B3DF23 /* OpenVPNPrivateKey.h */; settings = {ATTRIBUTES = (Public, ); }; }; C915F1F61F612F3300B3DF23 /* OpenVPNPrivateKey.m in Sources */ = {isa = PBXBuildFile; fileRef = C915F1F31F612F3300B3DF23 /* OpenVPNPrivateKey.m */; }; C915F1F71F612F3300B3DF23 /* OpenVPNPrivateKey.m in Sources */ = {isa = PBXBuildFile; fileRef = C915F1F31F612F3300B3DF23 /* OpenVPNPrivateKey.m */; }; C915F1F91F615BB400B3DF23 /* OpenVPNPrivateKeyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C915F1F81F615BB400B3DF23 /* OpenVPNPrivateKeyTests.swift */; }; From 9df7dee2dfdd94db23e394790edbf2495f3e6ece Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 13:56:46 +0300 Subject: [PATCH 26/42] Add OpenVPNPrivateKey.h to the umbrella header --- OpenVPN Adapter/Umbrella-Header.h | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenVPN Adapter/Umbrella-Header.h b/OpenVPN Adapter/Umbrella-Header.h index a0a5b77..333d46d 100644 --- a/OpenVPN Adapter/Umbrella-Header.h +++ b/OpenVPN Adapter/Umbrella-Header.h @@ -34,5 +34,6 @@ FOUNDATION_EXPORT const unsigned char OpenVPNAdapterVersionString[]; #import #import #import +#import #import #import From 6d0b1d28b084e614a58c6941bdd66d2c430f1b27 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 14:07:42 +0300 Subject: [PATCH 27/42] Implement parsing private key DER and PEM data --- OpenVPN Adapter/OpenVPNPrivateKey.m | 38 +++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/OpenVPN Adapter/OpenVPNPrivateKey.m b/OpenVPN Adapter/OpenVPNPrivateKey.m index 924b425..4963e3f 100644 --- a/OpenVPN Adapter/OpenVPNPrivateKey.m +++ b/OpenVPN Adapter/OpenVPNPrivateKey.m @@ -14,7 +14,7 @@ @interface OpenVPNPrivateKey () -@property (nonatomic, assign) mbedtls_pk_context *key; +@property (nonatomic, assign) mbedtls_pk_context *ctx; @end @@ -23,8 +23,8 @@ - (instancetype)init { self = [super init]; if (self) { - self.key = malloc(sizeof(mbedtls_pk_context)); - mbedtls_pk_init(self.key); + self.ctx = malloc(sizeof(mbedtls_pk_context)); + mbedtls_pk_init(self.ctx); } return self; } @@ -32,18 +32,46 @@ + (nullable OpenVPNPrivateKey *)keyWithPEM:(NSData *)pemData password:(NSString *)password error:(out NSError **)error { OpenVPNPrivateKey *key = [OpenVPNPrivateKey new]; + NSString *pemString = [[NSString alloc] initWithData:pemData encoding:NSUTF8StringEncoding]; + + int result = mbedtls_pk_parse_key(key.ctx, (const unsigned char *)pemString.UTF8String, pemData.length + 1, (const unsigned char *)password.UTF8String, password.length + 1); + if (result < 0) { + if (error) { + NSString *reason = [NSError reasonFromResult:result]; + *error = [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:result userInfo:@{ + NSLocalizedDescriptionKey: @"Failed to read PEM data.", + NSLocalizedFailureReasonErrorKey: reason + }]; + } + + return nil; + } + return key; } + (nullable OpenVPNPrivateKey *)keyWithDER:(NSData *)derData password:(NSString *)password error:(out NSError **)error { OpenVPNPrivateKey *key = [OpenVPNPrivateKey new]; + int result = mbedtls_pk_parse_key(key.ctx, derData.bytes, derData.length, (const unsigned char *)password.UTF8String, password.length + 1); + if (result < 0) { + if (error) { + NSString *reason = [NSError reasonFromResult:result]; + *error = [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:result userInfo:@{ + NSLocalizedDescriptionKey: @"Failed to read DER data.", + NSLocalizedFailureReasonErrorKey: reason + }]; + } + + return nil; + } + return key; } - (void)dealloc { - mbedtls_pk_free(self.key); - free(self.key); + mbedtls_pk_free(self.ctx); + free(self.ctx); } @end From a346e0c51aecbf6f1f8f39811a983c9b82b751f7 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 14:11:57 +0300 Subject: [PATCH 28/42] Free allocated PEM buffer --- OpenVPN Adapter/OpenVPNCertificate.m | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OpenVPN Adapter/OpenVPNCertificate.m b/OpenVPN Adapter/OpenVPNCertificate.m index 8789417..2a041be 100644 --- a/OpenVPN Adapter/OpenVPNCertificate.m +++ b/OpenVPN Adapter/OpenVPNCertificate.m @@ -90,10 +90,14 @@ }]; } + free(pem_buffer); return nil; } - return [NSData dataWithBytes:pem_buffer length:output_length - 1]; + NSData *pemData = [NSData dataWithBytes:pem_buffer length:output_length - 1]; + + free(pem_buffer); + return pemData; } - (NSData *)derData:(out NSError **)error { From 8ead0babeb7faa226b297e5c3155c19a7e9d066b Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 14:26:05 +0300 Subject: [PATCH 29/42] Return size of the key in bits --- OpenVPN Adapter/OpenVPNPrivateKey.h | 2 ++ OpenVPN Adapter/OpenVPNPrivateKey.m | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/OpenVPN Adapter/OpenVPNPrivateKey.h b/OpenVPN Adapter/OpenVPNPrivateKey.h index 9157862..eeda4ec 100644 --- a/OpenVPN Adapter/OpenVPNPrivateKey.h +++ b/OpenVPN Adapter/OpenVPNPrivateKey.h @@ -20,6 +20,8 @@ - (nonnull instancetype) __unavailable init; +@property (nonatomic, readonly) NSInteger size; + - (nullable NSData *)pemData:(out NSError * __nullable * __nullable)error; - (nullable NSData *)derData:(out NSError * __nullable * __nullable)error; diff --git a/OpenVPN Adapter/OpenVPNPrivateKey.m b/OpenVPN Adapter/OpenVPNPrivateKey.m index 4963e3f..a72d3e0 100644 --- a/OpenVPN Adapter/OpenVPNPrivateKey.m +++ b/OpenVPN Adapter/OpenVPNPrivateKey.m @@ -29,6 +29,10 @@ return self; } +- (NSInteger)size { + return mbedtls_pk_get_bitlen(self.ctx); +} + + (nullable OpenVPNPrivateKey *)keyWithPEM:(NSData *)pemData password:(NSString *)password error:(out NSError **)error { OpenVPNPrivateKey *key = [OpenVPNPrivateKey new]; From 519b8f62e6776bb20c1d8e25e94f4e6f6ff4bcb9 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 14:30:43 +0300 Subject: [PATCH 30/42] Add OpenVPNKeyType.h to the project --- OpenVPN Adapter.xcodeproj/project.pbxproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OpenVPN Adapter.xcodeproj/project.pbxproj b/OpenVPN Adapter.xcodeproj/project.pbxproj index 3b8a3d4..932f084 100644 --- a/OpenVPN Adapter.xcodeproj/project.pbxproj +++ b/OpenVPN Adapter.xcodeproj/project.pbxproj @@ -15,6 +15,8 @@ C915F1F71F612F3300B3DF23 /* OpenVPNPrivateKey.m in Sources */ = {isa = PBXBuildFile; fileRef = C915F1F31F612F3300B3DF23 /* OpenVPNPrivateKey.m */; }; C915F1F91F615BB400B3DF23 /* OpenVPNPrivateKeyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C915F1F81F615BB400B3DF23 /* OpenVPNPrivateKeyTests.swift */; }; C915F1FA1F615BB400B3DF23 /* OpenVPNPrivateKeyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C915F1F81F615BB400B3DF23 /* OpenVPNPrivateKeyTests.swift */; }; + C915F1FE1F6164CF00B3DF23 /* OpenVPNKeyType.h in Headers */ = {isa = PBXBuildFile; fileRef = C915F1FD1F6164CF00B3DF23 /* OpenVPNKeyType.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C915F1FF1F6164CF00B3DF23 /* OpenVPNKeyType.h in Headers */ = {isa = PBXBuildFile; fileRef = C915F1FD1F6164CF00B3DF23 /* OpenVPNKeyType.h */; settings = {ATTRIBUTES = (Public, ); }; }; C9354F451F1E4A4500F4C935 /* OpenVPNReachabilityStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = C9B795681F1D219C00CF35FE /* OpenVPNReachabilityStatus.h */; settings = {ATTRIBUTES = (Public, ); }; }; C9354F461F1E4A4600F4C935 /* OpenVPNReachabilityStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = C9B795681F1D219C00CF35FE /* OpenVPNReachabilityStatus.h */; settings = {ATTRIBUTES = (Public, ); }; }; C9354F471F1E4AE200F4C935 /* OpenVPNReachabilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9354F431F1E49A500F4C935 /* OpenVPNReachabilityTests.swift */; }; @@ -174,6 +176,7 @@ C915F1F21F612F3300B3DF23 /* OpenVPNPrivateKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenVPNPrivateKey.h; sourceTree = ""; }; C915F1F31F612F3300B3DF23 /* OpenVPNPrivateKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OpenVPNPrivateKey.m; sourceTree = ""; }; C915F1F81F615BB400B3DF23 /* OpenVPNPrivateKeyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenVPNPrivateKeyTests.swift; sourceTree = ""; }; + C915F1FD1F6164CF00B3DF23 /* OpenVPNKeyType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenVPNKeyType.h; sourceTree = ""; }; C9354F431F1E49A500F4C935 /* OpenVPNReachabilityTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenVPNReachabilityTests.swift; sourceTree = ""; }; C93779D31EAE32670030A362 /* OpenVPNCredentials.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenVPNCredentials.h; sourceTree = ""; }; C93779D41EAE32670030A362 /* OpenVPNCredentials.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = OpenVPNCredentials.mm; sourceTree = ""; }; @@ -376,6 +379,7 @@ C9657A631EB0D6AD00EFF210 /* OpenVPNCompressionMode.h */, C9657A661EB0D73200EFF210 /* OpenVPNMinTLSVersion.h */, C9657A691EB0D75700EFF210 /* OpenVPNTLSCertProfile.h */, + C915F1FD1F6164CF00B3DF23 /* OpenVPNKeyType.h */, C9B795681F1D219C00CF35FE /* OpenVPNReachabilityStatus.h */, ); name = "Types and Constants"; @@ -554,6 +558,7 @@ C9BCE25E1EB3C201009D6AC1 /* OpenVPNSessionToken+Internal.h in Headers */, C9BB47721E7171A100F3F98C /* OpenVPNAdapterEvent.h in Headers */, C9BB477F1E7173C700F3F98C /* OpenVPNAdapter.h in Headers */, + C915F1FE1F6164CF00B3DF23 /* OpenVPNKeyType.h in Headers */, C9657A4C1EB0CD6C00EFF210 /* OpenVPNProperties.h in Headers */, C9657A571EB0CDFB00EFF210 /* OpenVPNProperties+Internal.h in Headers */, C9BCE2581EB3C0D9009D6AC1 /* OpenVPNSessionToken.h in Headers */, @@ -598,6 +603,7 @@ C9BCE25F1EB3C201009D6AC1 /* OpenVPNSessionToken+Internal.h in Headers */, C9D2ABE41EA20F99007EDF9D /* OpenVPNAdapterEvent.h in Headers */, C9D2ABE51EA20F99007EDF9D /* OpenVPNAdapter.h in Headers */, + C915F1FF1F6164CF00B3DF23 /* OpenVPNKeyType.h in Headers */, C9657A4D1EB0CD6C00EFF210 /* OpenVPNProperties.h in Headers */, C9657A561EB0CDFA00EFF210 /* OpenVPNProperties+Internal.h in Headers */, C9BCE2591EB3C0D9009D6AC1 /* OpenVPNSessionToken.h in Headers */, From 1ddcad1487dc7a843983e45d149de9fcd1e70fc1 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 14:30:59 +0300 Subject: [PATCH 31/42] Define available key types --- OpenVPN Adapter/OpenVPNKeyType.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 OpenVPN Adapter/OpenVPNKeyType.h diff --git a/OpenVPN Adapter/OpenVPNKeyType.h b/OpenVPN Adapter/OpenVPNKeyType.h new file mode 100644 index 0000000..f1e6019 --- /dev/null +++ b/OpenVPN Adapter/OpenVPNKeyType.h @@ -0,0 +1,19 @@ +// +// OpenVPNKeyType.h +// OpenVPN Adapter +// +// Created by Sergey Abramchuk on 07.09.17. +// +// + +#import + +typedef NS_ENUM(NSInteger, OpenVPNKeyType) { + OpenVPNKeyTypeNone = 0, + OpenVPNKeyTypeRSA, + OpenVPNKeyTypeECKEY, + OpenVPNKeyTypeECKEYDH, + OpenVPNKeyTypeECDSA, + OpenVPNKeyTypeRSAALT, + OpenVPNKeyTypeRSASSAPSS, +} From 69718e1e74b4c05f7beabf7e80424f33cd9739b8 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 14:31:48 +0300 Subject: [PATCH 32/42] Add OpenVPNKeyType.h to the umbrella header --- OpenVPN Adapter/Umbrella-Header.h | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenVPN Adapter/Umbrella-Header.h b/OpenVPN Adapter/Umbrella-Header.h index 333d46d..640441d 100644 --- a/OpenVPN Adapter/Umbrella-Header.h +++ b/OpenVPN Adapter/Umbrella-Header.h @@ -33,6 +33,7 @@ FOUNDATION_EXPORT const unsigned char OpenVPNAdapterVersionString[]; #import #import #import +#import #import #import #import From 8b390e969ff522b36f4927dcb5ae508ab733a2ac Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 14:35:33 +0300 Subject: [PATCH 33/42] Return type of the key --- OpenVPN Adapter/OpenVPNPrivateKey.h | 3 +++ OpenVPN Adapter/OpenVPNPrivateKey.m | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/OpenVPN Adapter/OpenVPNPrivateKey.h b/OpenVPN Adapter/OpenVPNPrivateKey.h index eeda4ec..81ca5f6 100644 --- a/OpenVPN Adapter/OpenVPNPrivateKey.h +++ b/OpenVPN Adapter/OpenVPNPrivateKey.h @@ -8,6 +8,8 @@ #import +#import "OpenVPNKeyType.h" + @interface OpenVPNPrivateKey : NSObject + (nullable OpenVPNPrivateKey *)keyWithPEM:(nonnull NSData *)pemData @@ -21,6 +23,7 @@ - (nonnull instancetype) __unavailable init; @property (nonatomic, readonly) NSInteger size; +@property (nonatomic, readonly) OpenVPNKeyType type; - (nullable NSData *)pemData:(out NSError * __nullable * __nullable)error; - (nullable NSData *)derData:(out NSError * __nullable * __nullable)error; diff --git a/OpenVPN Adapter/OpenVPNPrivateKey.m b/OpenVPN Adapter/OpenVPNPrivateKey.m index a72d3e0..03f8c2e 100644 --- a/OpenVPN Adapter/OpenVPNPrivateKey.m +++ b/OpenVPN Adapter/OpenVPNPrivateKey.m @@ -33,6 +33,10 @@ return mbedtls_pk_get_bitlen(self.ctx); } +- (OpenVPNKeyType)type { + return (OpenVPNKeyType)mbedtls_pk_get_type(self.ctx); +} + + (nullable OpenVPNPrivateKey *)keyWithPEM:(NSData *)pemData password:(NSString *)password error:(out NSError **)error { OpenVPNPrivateKey *key = [OpenVPNPrivateKey new]; From 6b1b0c95ebed589391909b92002ccf72636fc8de Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 14:36:12 +0300 Subject: [PATCH 34/42] Add missing semicolon --- OpenVPN Adapter/OpenVPNKeyType.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenVPN Adapter/OpenVPNKeyType.h b/OpenVPN Adapter/OpenVPNKeyType.h index f1e6019..06d9243 100644 --- a/OpenVPN Adapter/OpenVPNKeyType.h +++ b/OpenVPN Adapter/OpenVPNKeyType.h @@ -16,4 +16,4 @@ typedef NS_ENUM(NSInteger, OpenVPNKeyType) { OpenVPNKeyTypeECDSA, OpenVPNKeyTypeRSAALT, OpenVPNKeyTypeRSASSAPSS, -} +}; From ebb21573902836a1c929747c379c0aacaa0b31db Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 14:50:08 +0300 Subject: [PATCH 35/42] Implement writing private key DER and PEM data --- OpenVPN Adapter/OpenVPNPrivateKey.m | 51 +++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/OpenVPN Adapter/OpenVPNPrivateKey.m b/OpenVPN Adapter/OpenVPNPrivateKey.m index 03f8c2e..c66c1aa 100644 --- a/OpenVPN Adapter/OpenVPNPrivateKey.m +++ b/OpenVPN Adapter/OpenVPNPrivateKey.m @@ -77,6 +77,57 @@ return key; } +- (NSData *)pemData:(out NSError **)error { + size_t buffer_length = (self.size / 8) * 2; + unsigned char *pem_buffer = malloc(buffer_length); + + int result = mbedtls_pk_write_key_pem(self.ctx, pem_buffer, buffer_length); + if (result < 0) { + if (error) { + NSString *reason = [NSError reasonFromResult:result]; + *error = [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:result userInfo:@{ + NSLocalizedDescriptionKey: @"Failed to write PEM data.", + NSLocalizedFailureReasonErrorKey: reason + }]; + } + + free(pem_buffer); + return nil; + } + + NSData *pemData = [[NSString stringWithCString:(const char *)pem_buffer encoding:NSUTF8StringEncoding] dataUsingEncoding:NSUTF8StringEncoding]; + + free(pem_buffer); + return pemData; +} + +- (NSData *)derData:(out NSError **)error { + size_t buffer_length = (self.size / 8) * 2; + unsigned char *der_buffer = malloc(buffer_length); + + int result = mbedtls_pk_write_key_der(self.ctx, der_buffer, buffer_length); + if (result < 0) { + if (error) { + NSString *reason = [NSError reasonFromResult:result]; + *error = [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:result userInfo:@{ + NSLocalizedDescriptionKey: @"Failed to write DER data.", + NSLocalizedFailureReasonErrorKey: reason + }]; + } + + free(der_buffer); + return nil; + } + + NSUInteger location = buffer_length - result; + NSRange range = NSMakeRange(location, result); + + NSData *derData = [[NSData dataWithBytes:der_buffer length:buffer_length] subdataWithRange:range]; + + free(der_buffer); + return derData; +} + - (void)dealloc { mbedtls_pk_free(self.ctx); free(self.ctx); From b5b8834c757d7349a360db3edf93b40fd2c8dedf Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 20:03:20 +0300 Subject: [PATCH 36/42] Add private key and certificate for testing --- OpenVPN Adapter Tests/Resources/ca.crt | 17 ----------------- OpenVPN Adapter Tests/Resources/ca.key | 15 --------------- .../Resources/keyfile-decrypted.3des | 15 +++++++++++++++ .../Resources/keyfile-encrypted.3des | 18 ++++++++++++++++++ OpenVPN Adapter Tests/Resources/test-ca.crt | 15 +++++++++++++++ 5 files changed, 48 insertions(+), 32 deletions(-) delete mode 100644 OpenVPN Adapter Tests/Resources/ca.crt delete mode 100644 OpenVPN Adapter Tests/Resources/ca.key create mode 100644 OpenVPN Adapter Tests/Resources/keyfile-decrypted.3des create mode 100644 OpenVPN Adapter Tests/Resources/keyfile-encrypted.3des create mode 100644 OpenVPN Adapter Tests/Resources/test-ca.crt diff --git a/OpenVPN Adapter Tests/Resources/ca.crt b/OpenVPN Adapter Tests/Resources/ca.crt deleted file mode 100644 index 13916da..0000000 --- a/OpenVPN Adapter Tests/Resources/ca.crt +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICvDCCAiWgAwIBAgIJAIk6JnSDG7spMA0GCSqGSIb3DQEBBQUAMEkxCzAJBgNV -BAYTAlJVMRMwEQYDVQQIEwpTb21lLVN0YXRlMRQwEgYDVQQHEwtBcmtoYW5nZWxz -azEPMA0GA1UEChMGUy1USUNLMB4XDTE3MDkwNjE0MDc1MVoXDTE3MTAwNjE0MDc1 -MVowSTELMAkGA1UEBhMCUlUxEzARBgNVBAgTClNvbWUtU3RhdGUxFDASBgNVBAcT -C0Fya2hhbmdlbHNrMQ8wDQYDVQQKEwZTLVRJQ0swgZ8wDQYJKoZIhvcNAQEBBQAD -gY0AMIGJAoGBAMXgr0CSQmXqzeYv3tqHDVeAnjt2eFlFya1RJIE59Vu3quAD/6Us -fM2VUAtjRu+Bh8QYefsJ5IBpT7AnaUi5TM0XDBW9iPxxXus2l0QtCiCf/JDEDk19 -Ig5e4lbJMwR/QuEw6LceVXmcxIYsZBnw4Ni7DcXbBeLKuEQuiUOMXcqrAgMBAAGj -gaswgagwHQYDVR0OBBYEFE4iwGwZysk3DA8xMI9lM1yljKtVMHkGA1UdIwRyMHCA -FE4iwGwZysk3DA8xMI9lM1yljKtVoU2kSzBJMQswCQYDVQQGEwJSVTETMBEGA1UE -CBMKU29tZS1TdGF0ZTEUMBIGA1UEBxMLQXJraGFuZ2Vsc2sxDzANBgNVBAoTBlMt -VElDS4IJAIk6JnSDG7spMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEA -iBlchqANsArwiY6xO3rpWsuvOQaijUY0DicHnzriEcrD3XATRKllQ6vekXHolsKl -1tq88AmNhn95s9zOgEGrFftvb06UwZ/zGiuXlUPTkiFxOP3rqXmYG9pn431DhMfm -rr2dVN0/94np8jELlpnxFiB79GWSPjVOfXDmZ266oD4= ------END CERTIFICATE----- diff --git a/OpenVPN Adapter Tests/Resources/ca.key b/OpenVPN Adapter Tests/Resources/ca.key deleted file mode 100644 index bff2359..0000000 --- a/OpenVPN Adapter Tests/Resources/ca.key +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDF4K9AkkJl6s3mL97ahw1XgJ47dnhZRcmtUSSBOfVbt6rgA/+l -LHzNlVALY0bvgYfEGHn7CeSAaU+wJ2lIuUzNFwwVvYj8cV7rNpdELQogn/yQxA5N -fSIOXuJWyTMEf0LhMOi3HlV5nMSGLGQZ8ODYuw3F2wXiyrhELolDjF3KqwIDAQAB -AoGAUPOBXr43EbDEeSYeWnIjoCeLFDJ8O7FUN2ZZs9A9Mz9pVWntXOpdSFGMRIxh -ybvJCg0lYfEDHRF4O010Qf8kjo5Y+KRUJgV7J3HG4O8XkpYBnNMJa1wJYBdreFe2 -iUgcEaBRK55LOOftiE34dLQMgJlaySuNBtfNlORlqJJ0Z6kCQQDpNgeEdytUbjx+ -aJhnxNtXy6yJ0EUKoDPi9xKpa3K7ZxB6tfA+B+WtgLKWfFSorK9P3cSH9B0Pr2OO -MGK2x2PPAkEA2TbC05eQ/XUqiH6yvbtss5Q73YabIj8g6hd6IyHW2b10Qt27CCZS -pEwB16XXtJqXCOcqY3spuORM/Y14f652ZQJAdjc6Jk7WOw1KQvW4U9m5Kk8HXjCh -3toIk0OVRSY/WXnMI7f4WSldps63OIs7yukGUSDkj9oRpTLN73TdhTObhwJBANbb -fhfCot6zWOEvQiq/DCUOCbF0hlt3yl0D4AKEZHt5FVlW7rx++9wceu4O07GIAMID -t0A0Ae8rlKRxnbHepqkCQD+XNnuUSi+zJB07Qmsx1ywQr9zH4lDVuZ660LELWYPr -rp8x07XiCFKvmGWDLuKsEBzj5eBwqlTUywwjhwYm8Xo= ------END RSA PRIVATE KEY----- diff --git a/OpenVPN Adapter Tests/Resources/keyfile-decrypted.3des b/OpenVPN Adapter Tests/Resources/keyfile-decrypted.3des new file mode 100644 index 0000000..f54d47a --- /dev/null +++ b/OpenVPN Adapter Tests/Resources/keyfile-decrypted.3des @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDMYfnvWtC8Id5bPKae5yXSxQTt+Zpul6AnnZWfI2TtIarvjHBF +UtXRo96y7hoL4VWOPKGCsRqMFDkrbeUjRrx8iL914/srnyf6sh9c8Zk04xEOpK1y +pvBz+Ks4uZObtjnnitf0NBGdjMKxveTq+VE7BWUIyQjtQ8mbDOsiLLvh7wIDAQAB +AoGAefPIT8MPpAJNjIE/JrfkAMTgsSLrvCurO5gzDBbxhPE+7tsMrsDDpuix3HBo +iEg3ZbzV3obQwV7b0gcr34W4t0CMuJf5b5irHRG8JcZuncmofDy6z7S5Vs75O85z +fVzTIuVUyuHy1rM6rSBYKfsMLVyImUb4wtIXEMHPzdCL9LECQQD3ZfgGqudMWq8v +3BlKhsQ4fsR0vxzNlMZfoRrZzcvBT339Bp1UQ8aUo8xBtHiRwuW1NaPNgYKX6XQ6 +ppuWuTiJAkEA030i493KnFPLRwWypqF/s6ZNlVye+euFN5NF/IeJcvb/GUDRYv9O +pRozRS1jNx4ZB1K2xT7N9MwsPHD6j6K4twJBALdfHTfT9RzjGnae7SAQQ+CcFYFz +JiY6386B2yUVJLFj+j5RaMvMcKQ7xGnvGm7vxtNJrt/j3qg6oavXUfulzgECQQDP +CEVLhCd/+ZeZoz5MWPTGTRrOCKmoRqNW0FlG6PfpD1qSwh04KG44uflO0yu5HUGr +JZG+bcj4x5bWZFMkoUrpAkEAyEgQzesKFqcbt1cqv3pLXJYQBBw6leFXgHk11a7k ++AkexhrPYyq/4tXFO2TLk2hs7tpYgNDOqZCvEu7jtN3RuA== +-----END RSA PRIVATE KEY----- diff --git a/OpenVPN Adapter Tests/Resources/keyfile-encrypted.3des b/OpenVPN Adapter Tests/Resources/keyfile-encrypted.3des new file mode 100644 index 0000000..638c19a --- /dev/null +++ b/OpenVPN Adapter Tests/Resources/keyfile-encrypted.3des @@ -0,0 +1,18 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,BE8274D6692AF2A7 + +9ZXjoF55A9XgJpdaWmF/ZL1sJfbnE1M42N7HHRDwpq1/K+afC9poM0/AdCUbRL7w +uvQERievbAYpNeLdah1EftM6033e1oTxUMivdL4orDKcbb3qDpSQ0o0UbjavbT+d +aruilW8zVP4dz3mYMvGbkgoujgzdT+4wM0T1mTTuYcRKQsHlg7QDy2QrBILNuXA4 +Hmye4GlSXVUSON8vPXT12V4oeubEIZVlnkLTRFGRVA4qz5tby9GBymkeNCBu+LCw +JwJLTbQwMFqozHvioq/2YBaHDcySpTD4X5AwrCjifUNO9BnLWLAmt8dOWr0z+48E +P/yWr5xZl3DrKh9r9EGb9xbTxhum3yHV7bvXLoUH+t9gowmd4Lq3Qjjf8jQXle0P +zoCOVxwN1E1IMhleEUPV7L8mbt26b0JyvrSS5ByrXahGu9vGQyy7qqx9ZANkzgXF +3hPMDuzQXMJiUeG92VsMEdGdA1/8V5ro+ceB5c7Zca5MjMzvx2tihda7BUjj6dSE +cA8Vvksy/NX/nqHSt0aSgphvBmZP8dN6GMcZ+hT7p0fhCq4mSFEykQqueKXiFUfz +0xCUVZC6WzOoEkc8k7xiLWQDlsZZ13Z4yxU1IxJp7llZXpZ8GkwS+678/Nx8h54A +mv5ZlSFWWQrvN5JPQJka7aU2ITu1LUK6mXBu+DoSDOfQuqR4vQytkjOqHK185iHs +JQtBGkFFdElkWgubPX/S8/xxoT8MoQY/c+dr6iwcswyUnSJXh32KLPGNBoqWCCbY +jp/VYmeb117gNpEJKJhcNbrP7DoQrC3/D7JFXnOvTA/z6FOtUmz0rQ== +-----END RSA PRIVATE KEY----- diff --git a/OpenVPN Adapter Tests/Resources/test-ca.crt b/OpenVPN Adapter Tests/Resources/test-ca.crt new file mode 100644 index 0000000..d41a420 --- /dev/null +++ b/OpenVPN Adapter Tests/Resources/test-ca.crt @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICUjCCAdegAwIBAgIJAMFD4n5iQ8zoMAoGCCqGSM49BAMCMD4xCzAJBgNVBAYT +Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF +QyBDQTAeFw0xMzA5MjQxNTQ5NDhaFw0yMzA5MjIxNTQ5NDhaMD4xCzAJBgNVBAYT +Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF +QyBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMPaKzRBN1gvh1b+/Im6KUNLTuBu +ww5XUzM5WNRStJGVOQsj318XJGJI/BqVKc4sLYfCiFKAr9ZqqyHduNMcbli4yuiy +aY7zQa0pw7RfdadHb9UZKVVpmlM7ILRmFmAzHqOBoDCBnTAdBgNVHQ4EFgQUnW0g +JEkBPyvLeLUZvH4kydv7NnwwbgYDVR0jBGcwZYAUnW0gJEkBPyvLeLUZvH4kydv7 +NnyhQqRAMD4xCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UE +AxMTUG9sYXJzc2wgVGVzdCBFQyBDQYIJAMFD4n5iQ8zoMAwGA1UdEwQFMAMBAf8w +CgYIKoZIzj0EAwIDaQAwZgIxAMO0YnNWKJUAfXgSJtJxexn4ipg+kv4znuR50v56 +t4d0PCu412mUC6Nnd7izvtE2MgIxAP1nnJQjZ8BWukszFQDG48wxCCyci9qpdSMv +uCjn8pwUOkABXK8Mss90fzCfCEOtIA== +-----END CERTIFICATE----- From 5746b24e5f2d49e887bb562a80e8b4008526c727 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 20:04:32 +0300 Subject: [PATCH 37/42] Fix incorrect password length and increase size of the buffers --- OpenVPN Adapter/OpenVPNPrivateKey.m | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/OpenVPN Adapter/OpenVPNPrivateKey.m b/OpenVPN Adapter/OpenVPNPrivateKey.m index c66c1aa..f1413c3 100644 --- a/OpenVPN Adapter/OpenVPNPrivateKey.m +++ b/OpenVPN Adapter/OpenVPNPrivateKey.m @@ -42,7 +42,10 @@ NSString *pemString = [[NSString alloc] initWithData:pemData encoding:NSUTF8StringEncoding]; - int result = mbedtls_pk_parse_key(key.ctx, (const unsigned char *)pemString.UTF8String, pemData.length + 1, (const unsigned char *)password.UTF8String, password.length + 1); + size_t pem_length = strlen(pemString.UTF8String) + 1; + size_t password_length = password != nil ? strlen(password.UTF8String) : 0; + + int result = mbedtls_pk_parse_key(key.ctx, (const unsigned char *)pemString.UTF8String, pem_length, (const unsigned char *)password.UTF8String, password_length); if (result < 0) { if (error) { NSString *reason = [NSError reasonFromResult:result]; @@ -61,7 +64,9 @@ + (nullable OpenVPNPrivateKey *)keyWithDER:(NSData *)derData password:(NSString *)password error:(out NSError **)error { OpenVPNPrivateKey *key = [OpenVPNPrivateKey new]; - int result = mbedtls_pk_parse_key(key.ctx, derData.bytes, derData.length, (const unsigned char *)password.UTF8String, password.length + 1); + size_t password_length = password != nil ? strlen(password.UTF8String) : 0; + + int result = mbedtls_pk_parse_key(key.ctx, derData.bytes, derData.length, (const unsigned char *)password.UTF8String, password_length); if (result < 0) { if (error) { NSString *reason = [NSError reasonFromResult:result]; @@ -78,8 +83,8 @@ } - (NSData *)pemData:(out NSError **)error { - size_t buffer_length = (self.size / 8) * 2; - unsigned char *pem_buffer = malloc(buffer_length); + size_t buffer_length = mbedtls_pk_get_len(self.ctx) * 10; + unsigned char *pem_buffer = calloc(buffer_length, sizeof(unsigned char)); int result = mbedtls_pk_write_key_pem(self.ctx, pem_buffer, buffer_length); if (result < 0) { @@ -102,8 +107,8 @@ } - (NSData *)derData:(out NSError **)error { - size_t buffer_length = (self.size / 8) * 2; - unsigned char *der_buffer = malloc(buffer_length); + size_t buffer_length = mbedtls_pk_get_len(self.ctx) * 10; + unsigned char *der_buffer = calloc(buffer_length, sizeof(unsigned char)); int result = mbedtls_pk_write_key_der(self.ctx, der_buffer, buffer_length); if (result < 0) { From edea44cd0a3bc0a0b67db7f8ae74db1aaad7fee6 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 20:08:54 +0300 Subject: [PATCH 38/42] Increase buffer length --- OpenVPN Adapter/OpenVPNCertificate.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenVPN Adapter/OpenVPNCertificate.m b/OpenVPN Adapter/OpenVPNCertificate.m index 2a041be..ca23293 100644 --- a/OpenVPN Adapter/OpenVPNCertificate.m +++ b/OpenVPN Adapter/OpenVPNCertificate.m @@ -75,7 +75,7 @@ NSString *header = @"-----BEGIN CERTIFICATE-----\n"; NSString *footer = @"-----END CERTIFICATE-----\n"; - size_t buffer_length = self.crt->raw.len * 2; + size_t buffer_length = self.crt->raw.len * 10; unsigned char *pem_buffer = malloc(buffer_length); size_t output_length = 0; From cd1390fb46d0e5f749edaa5d4b26404bfa16a81d Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 20:09:14 +0300 Subject: [PATCH 39/42] Use malloc instead of calloc --- OpenVPN Adapter/OpenVPNPrivateKey.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenVPN Adapter/OpenVPNPrivateKey.m b/OpenVPN Adapter/OpenVPNPrivateKey.m index f1413c3..96100d8 100644 --- a/OpenVPN Adapter/OpenVPNPrivateKey.m +++ b/OpenVPN Adapter/OpenVPNPrivateKey.m @@ -84,7 +84,7 @@ - (NSData *)pemData:(out NSError **)error { size_t buffer_length = mbedtls_pk_get_len(self.ctx) * 10; - unsigned char *pem_buffer = calloc(buffer_length, sizeof(unsigned char)); + unsigned char *pem_buffer = malloc(buffer_length); int result = mbedtls_pk_write_key_pem(self.ctx, pem_buffer, buffer_length); if (result < 0) { @@ -108,7 +108,7 @@ - (NSData *)derData:(out NSError **)error { size_t buffer_length = mbedtls_pk_get_len(self.ctx) * 10; - unsigned char *der_buffer = calloc(buffer_length, sizeof(unsigned char)); + unsigned char *der_buffer = malloc(buffer_length); int result = mbedtls_pk_write_key_der(self.ctx, der_buffer, buffer_length); if (result < 0) { From 3b9bba9e21719da2430b0d3e1392a3a8b72f76b7 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 20:10:30 +0300 Subject: [PATCH 40/42] Update name of test certificate --- OpenVPN Adapter Tests/OpenVPNCertificateTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenVPN Adapter Tests/OpenVPNCertificateTests.swift b/OpenVPN Adapter Tests/OpenVPNCertificateTests.swift index 8fb1016..9bb4ee5 100644 --- a/OpenVPN Adapter Tests/OpenVPNCertificateTests.swift +++ b/OpenVPN Adapter Tests/OpenVPNCertificateTests.swift @@ -23,7 +23,7 @@ class OpenVPNCertificateTests: XCTestCase { func testCertificatePEMandDER() { guard - let caURL = Bundle.current.url(forResource: "ca", withExtension: "crt"), + let caURL = Bundle.current.url(forResource: "test-ca", withExtension: "crt"), let caOriginalPEMData = try? Data(contentsOf: caURL) else { XCTFail() From 8af3fab41e5982917f4996f0cd2102deebf03066 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 20:11:05 +0300 Subject: [PATCH 41/42] Add test of parsing private key PEM and DER data --- .../OpenVPNPrivateKeyTests.swift | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 OpenVPN Adapter Tests/OpenVPNPrivateKeyTests.swift diff --git a/OpenVPN Adapter Tests/OpenVPNPrivateKeyTests.swift b/OpenVPN Adapter Tests/OpenVPNPrivateKeyTests.swift new file mode 100644 index 0000000..ab45614 --- /dev/null +++ b/OpenVPN Adapter Tests/OpenVPNPrivateKeyTests.swift @@ -0,0 +1,124 @@ +// +// OpenVPNPrivateKeyTests.swift +// OpenVPN Adapter +// +// Created by Sergey Abramchuk on 07.09.17. +// +// + +import XCTest +@testable import OpenVPNAdapter + +class OpenVPNPrivateKeyTests: XCTestCase { + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testKeyPEMandDERWithoutPassword() { + guard + let caURL = Bundle.current.url(forResource: "keyfile-decrypted", withExtension: "3des"), + let caOriginalPEMData = try? Data(contentsOf: caURL) + else { + XCTFail() + return + } + + let keyFromPEM: OpenVPNPrivateKey + do { + keyFromPEM = try OpenVPNPrivateKey(pem: caOriginalPEMData, password: nil) + } catch { + XCTFail("\(error)") + return + } + + XCTAssert(keyFromPEM.type == .RSA) + + let keyDERData: Data + do { + keyDERData = try keyFromPEM.derData() + } catch { + XCTFail("\(error)") + return + } + + let keyFromDER: OpenVPNPrivateKey + do { + keyFromDER = try OpenVPNPrivateKey(der: keyDERData, password: nil) + } catch { + XCTFail("\(error)") + return + } + + XCTAssert(keyFromDER.type == .RSA) + + let keyGeneratedPEMData: Data + do { + keyGeneratedPEMData = try keyFromDER.pemData() + } catch { + XCTFail("\(error)") + return + } + + XCTAssert(keyGeneratedPEMData.elementsEqual(caOriginalPEMData)) + } + + func testKeyPEMandDERWithPassword() { + guard + let keyURL = Bundle.current.url(forResource: "keyfile-encrypted", withExtension: "3des"), + let keyOriginalPEMData = try? Data(contentsOf: keyURL) + else { + XCTFail() + return + } + + let keyFromPEM: OpenVPNPrivateKey + do { + keyFromPEM = try OpenVPNPrivateKey(pem: keyOriginalPEMData, password: "testkey") + } catch { + XCTFail("\(error)") + return + } + + let keyDERData: Data + do { + keyDERData = try keyFromPEM.derData() + } catch { + XCTFail("\(error)") + return + } + + let keyFromDER: OpenVPNPrivateKey + do { + keyFromDER = try OpenVPNPrivateKey(der: keyDERData, password: nil) + } catch { + XCTFail("\(error)") + return + } + + let keyGeneratedPEMData: Data + do { + keyGeneratedPEMData = try keyFromDER.pemData() + } catch { + XCTFail("\(error)") + return + } + + guard + let keySampleURL = Bundle.current.url(forResource: "keyfile-decrypted", withExtension: "3des"), + let keySamplePEMData = try? Data(contentsOf: keySampleURL) + else { + XCTFail() + return + } + + XCTAssert(keyGeneratedPEMData.elementsEqual(keySamplePEMData)) + } + +} From d747d1f61347eeafc9d710803d44cbcb590a73f4 Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Thu, 7 Sep 2017 20:11:20 +0300 Subject: [PATCH 42/42] Update project configuration --- OpenVPN Adapter.xcodeproj/project.pbxproj | 30 ++++++++++++++--------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/OpenVPN Adapter.xcodeproj/project.pbxproj b/OpenVPN Adapter.xcodeproj/project.pbxproj index 932f084..9fceffe 100644 --- a/OpenVPN Adapter.xcodeproj/project.pbxproj +++ b/OpenVPN Adapter.xcodeproj/project.pbxproj @@ -17,6 +17,12 @@ C915F1FA1F615BB400B3DF23 /* OpenVPNPrivateKeyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C915F1F81F615BB400B3DF23 /* OpenVPNPrivateKeyTests.swift */; }; C915F1FE1F6164CF00B3DF23 /* OpenVPNKeyType.h in Headers */ = {isa = PBXBuildFile; fileRef = C915F1FD1F6164CF00B3DF23 /* OpenVPNKeyType.h */; settings = {ATTRIBUTES = (Public, ); }; }; C915F1FF1F6164CF00B3DF23 /* OpenVPNKeyType.h in Headers */ = {isa = PBXBuildFile; fileRef = C915F1FD1F6164CF00B3DF23 /* OpenVPNKeyType.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C915F21F1F6199E300B3DF23 /* keyfile-encrypted.3des in Resources */ = {isa = PBXBuildFile; fileRef = C915F21E1F6199E300B3DF23 /* keyfile-encrypted.3des */; }; + C915F2201F6199E300B3DF23 /* keyfile-encrypted.3des in Resources */ = {isa = PBXBuildFile; fileRef = C915F21E1F6199E300B3DF23 /* keyfile-encrypted.3des */; }; + C915F2221F61B0E700B3DF23 /* keyfile-decrypted.3des in Resources */ = {isa = PBXBuildFile; fileRef = C915F2211F61B0E700B3DF23 /* keyfile-decrypted.3des */; }; + C915F2231F61B0E700B3DF23 /* keyfile-decrypted.3des in Resources */ = {isa = PBXBuildFile; fileRef = C915F2211F61B0E700B3DF23 /* keyfile-decrypted.3des */; }; + C915F2251F61B22300B3DF23 /* test-ca.crt in Resources */ = {isa = PBXBuildFile; fileRef = C915F2241F61B22300B3DF23 /* test-ca.crt */; }; + C915F2261F61B22300B3DF23 /* test-ca.crt in Resources */ = {isa = PBXBuildFile; fileRef = C915F2241F61B22300B3DF23 /* test-ca.crt */; }; C9354F451F1E4A4500F4C935 /* OpenVPNReachabilityStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = C9B795681F1D219C00CF35FE /* OpenVPNReachabilityStatus.h */; settings = {ATTRIBUTES = (Public, ); }; }; C9354F461F1E4A4600F4C935 /* OpenVPNReachabilityStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = C9B795681F1D219C00CF35FE /* OpenVPNReachabilityStatus.h */; settings = {ATTRIBUTES = (Public, ); }; }; C9354F471F1E4AE200F4C935 /* OpenVPNReachabilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9354F431F1E49A500F4C935 /* OpenVPNReachabilityTests.swift */; }; @@ -116,10 +122,6 @@ C9CA4DD41F602F7B00C4F184 /* OpenVPNCertificate.h in Headers */ = {isa = PBXBuildFile; fileRef = C9CA4DD11F602F7B00C4F184 /* OpenVPNCertificate.h */; settings = {ATTRIBUTES = (Public, ); }; }; C9CA4DD51F602F7B00C4F184 /* OpenVPNCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = C9CA4DD21F602F7B00C4F184 /* OpenVPNCertificate.m */; }; C9CA4DD61F602F7B00C4F184 /* OpenVPNCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = C9CA4DD21F602F7B00C4F184 /* OpenVPNCertificate.m */; }; - C9CA4DD91F6038F000C4F184 /* ca.key in Resources */ = {isa = PBXBuildFile; fileRef = C9CA4DD71F6038F000C4F184 /* ca.key */; }; - C9CA4DDA1F6038F000C4F184 /* ca.key in Resources */ = {isa = PBXBuildFile; fileRef = C9CA4DD71F6038F000C4F184 /* ca.key */; }; - C9CA4DDB1F6038F000C4F184 /* ca.crt in Resources */ = {isa = PBXBuildFile; fileRef = C9CA4DD81F6038F000C4F184 /* ca.crt */; }; - C9CA4DDC1F6038F000C4F184 /* ca.crt in Resources */ = {isa = PBXBuildFile; fileRef = C9CA4DD81F6038F000C4F184 /* ca.crt */; }; C9CA4DE11F603A5300C4F184 /* OpenVPNCertificateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9CA4DE01F603A5300C4F184 /* OpenVPNCertificateTests.swift */; }; C9CA4DE21F603A5300C4F184 /* OpenVPNCertificateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9CA4DE01F603A5300C4F184 /* OpenVPNCertificateTests.swift */; }; C9D2ABDB1EA20F99007EDF9D /* OpenVPNAdapter.mm in Sources */ = {isa = PBXBuildFile; fileRef = C9BB477E1E7173C700F3F98C /* OpenVPNAdapter.mm */; }; @@ -177,6 +179,9 @@ C915F1F31F612F3300B3DF23 /* OpenVPNPrivateKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OpenVPNPrivateKey.m; sourceTree = ""; }; C915F1F81F615BB400B3DF23 /* OpenVPNPrivateKeyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenVPNPrivateKeyTests.swift; sourceTree = ""; }; C915F1FD1F6164CF00B3DF23 /* OpenVPNKeyType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenVPNKeyType.h; sourceTree = ""; }; + C915F21E1F6199E300B3DF23 /* keyfile-encrypted.3des */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "keyfile-encrypted.3des"; sourceTree = ""; }; + C915F2211F61B0E700B3DF23 /* keyfile-decrypted.3des */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "keyfile-decrypted.3des"; sourceTree = ""; }; + C915F2241F61B22300B3DF23 /* test-ca.crt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "test-ca.crt"; sourceTree = ""; }; C9354F431F1E49A500F4C935 /* OpenVPNReachabilityTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenVPNReachabilityTests.swift; sourceTree = ""; }; C93779D31EAE32670030A362 /* OpenVPNCredentials.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenVPNCredentials.h; sourceTree = ""; }; C93779D41EAE32670030A362 /* OpenVPNCredentials.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = OpenVPNCredentials.mm; sourceTree = ""; }; @@ -234,8 +239,6 @@ C9BDB1341EBCC3B900C204FF /* OpenVPNTunnelSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OpenVPNTunnelSettings.m; sourceTree = ""; }; C9CA4DD11F602F7B00C4F184 /* OpenVPNCertificate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenVPNCertificate.h; sourceTree = ""; }; C9CA4DD21F602F7B00C4F184 /* OpenVPNCertificate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OpenVPNCertificate.m; sourceTree = ""; }; - C9CA4DD71F6038F000C4F184 /* ca.key */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ca.key; sourceTree = ""; }; - C9CA4DD81F6038F000C4F184 /* ca.crt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ca.crt; sourceTree = ""; }; C9CA4DE01F603A5300C4F184 /* OpenVPNCertificateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenVPNCertificateTests.swift; sourceTree = ""; }; C9D2ABF01EA20F99007EDF9D /* OpenVPNAdapter.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OpenVPNAdapter.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C9D2ABFF1EA212A3007EDF9D /* OpenVPNAdapterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OpenVPNAdapterTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -471,8 +474,9 @@ C9BB479A1E71836100F3F98C /* Resources */ = { isa = PBXGroup; children = ( - C9CA4DD71F6038F000C4F184 /* ca.key */, - C9CA4DD81F6038F000C4F184 /* ca.crt */, + C915F2241F61B22300B3DF23 /* test-ca.crt */, + C915F21E1F6199E300B3DF23 /* keyfile-encrypted.3des */, + C915F2211F61B0E700B3DF23 /* keyfile-decrypted.3des */, C98467A11EAA559B00272A9A /* local_vpn_server.ovpn */, ); path = Resources; @@ -775,8 +779,9 @@ buildActionMask = 2147483647; files = ( C98467A21EAA559B00272A9A /* local_vpn_server.ovpn in Resources */, - C9CA4DDB1F6038F000C4F184 /* ca.crt in Resources */, - C9CA4DD91F6038F000C4F184 /* ca.key in Resources */, + C915F2221F61B0E700B3DF23 /* keyfile-decrypted.3des in Resources */, + C915F2251F61B22300B3DF23 /* test-ca.crt in Resources */, + C915F21F1F6199E300B3DF23 /* keyfile-encrypted.3des in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -792,8 +797,9 @@ buildActionMask = 2147483647; files = ( C98467A31EAA559B00272A9A /* local_vpn_server.ovpn in Resources */, - C9CA4DDC1F6038F000C4F184 /* ca.crt in Resources */, - C9CA4DDA1F6038F000C4F184 /* ca.key in Resources */, + C915F2231F61B0E700B3DF23 /* keyfile-decrypted.3des in Resources */, + C915F2261F61B22300B3DF23 /* test-ca.crt in Resources */, + C915F2201F6199E300B3DF23 /* keyfile-encrypted.3des in Resources */, ); runOnlyForDeploymentPostprocessing = 0; };