Building VPN, what to choose?

Hello

Few week ago I am was began create vpn for ios.
I am was try create vpn use NEVPNManager with IKEv2 protocol but I am have trouble with certificate in iOS( because need certificate from CA ).
Second which I am try was be create VPN use NETunnelProvider bu I am also can't create vpn. Also I am use information from other sources, but each time I am failed.
Last time I am use AlgoVPN on my server with ubuntu and programmatically create vpn profile on ios, but I can't use this auth method without certificate and it's trouble for me.

How I can create vpn only with login and password authentication method without any certificate?
My app give access to blocked site in my country and I am need programmatically enable and disable vpn client.
Now I am want use WireGuard but I don't know can I create or not vpn client.

I am don't have many experince with these complex tasks, if you know how create vpn without pain please give me advice, should I am use this way or some else.

Regards, Ihor.

Answered by Systems Engineer in 640253022

I am examine more detail server side log, and saw that I am have connection to vpn but only on few second then I am automatic disconnected but I am don't understand why?

It sounds like you are getting closer on the server side. Try and track down the exact timestamp when you noticed the VPN connected and check your server logs and also the logs for your VPN in the Console.app. There should be something for you to go on here.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
One technique you can take here for NEVPNManager is to try and use a VPN profile that you setup with Apple Configurator 2 against your VPN server. From here, if you can connect and you can verify that you are passing traffic through your tunnel to your server you should be able to then reverse the profile settings into a standard API configuration using NEVPNManager, NEVPNProtocol, and NEVPNProtocolIKEv2.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
I not completely understand all picture, what this technique can give me, please explain me more detail, I am did try create vpn profile use NEVPNManager with IKEv2 protocol use all data from my .mobileconfig which was be generated with my server but it doesn't work because I also have problem with certificate.

But I can use vpn with .mobileconfig and iPhone but without opportunity programmatically enable and disable vpn, it’s main goal for my app, I am don’t do anything with traffic and don’t use app for pass any sensitive info, I am only give access to blocked particular site if him don’t available.

I can get access to vpn setting if I am install him use file .mobileconfig which was be download from WWW?

With standard .mobileconfig from server, traffic pass through and all work good I am have access to web site if content blocked but can’t programmatically enable and disable it.

Regards, Ihor.

I am did try create vpn profile use NEVPNManager with IKEv2 protocol use all data from my .mobileconfig which was be generated with my server but it doesn't work because I also have problem with certificate.

But I can use vpn with .mobileconfig and iPhone but without opportunity programmatically enable and disable vpn, it’s main goal for my app, I am don’t do anything with traffic and don’t use app for pass any sensitive info, I am only give access to blocked particular site if him don’t available.

Okay, it sounds like you are able to get the personal VPN up and running with the .mobileconfig but are having certificate issues when migrating to the API version of the personal VPN. This would then fall in line with this post as well. Combing the two, you are approaching the personal VPN route from the correct direction. Getting a working configuration going and then reversing that configuration into an API definition was my recommendation here. The certificate issue looks to be coming from here (referencing your other post):

Code Block swift
IKEv2Protocol.identityDataPassword = self.p12Password
IKEv2Protocol.identityData = self.dataFromFile() as Data


And this is where I would concentrate my debugging for now. Note that it looks like you are loading the PKCS12 from disk and not from the keychain so check to see if SecItemCopyMatching is needed in this situation.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Thanks I am understand, I am examine it more detail, but when I am did get problem with certificate I am tried two way how load certificate:

First way -
Code Block
let urlPath = Bundle.main.url(forResource: "client", withExtension: "p12")
let url = URL(string: urlPath!.description)
 ...
let certData = try Data(contentsOf: url!)
...
providerProtocol.identityReference = self.identityReference(for: certData, password: "********")
private func identityReference(for pkcs12Data: Data, password: String) -> Data {
    var importResult: CFArray? = nil
    let err = SecPKCS12Import(pkcs12Data as NSData, [
      kSecImportExportPassphrase: password
    ] as NSDictionary, &importResult)
    guard err == errSecSuccess else { fatalError() }
    let importArray = importResult! as! [[String:Any]]
    let identity = importArray[0][kSecImportItemIdentity as String]! as! SecIdentity
    var copyResult: CFTypeRef? = nil
    let err2 = SecItemCopyMatching([
      kSecValueRef: identity,
      kSecReturnPersistentRef: true
    ] as NSDictionary, &copyResult)
    guard err2 == errSecSuccess else { fatalError() }
    return copyResult! as! Data
  }


and
Second way -
Code Block
IKEv2Protocol.identityDataPassword = self.p12Password
IKEv2Protocol.identityData = self.dataFromFile() as Data
func dataFromFile() -> NSData{
    let rootCertPath = Bundle.main.path(forResource: "client", ofType: "p12")
    let certficiateData = NSData(contentsOfFile: rootCertPath!)
    return certficiateData!
  }

It's equivalent operation I am right, second way only more elegant?
I am put my certificate like local file in folder inside xcode.
If yes why I am have problem with certificate when use both ways or I am mistakes?

And please clarify me about one thing, when I am build VPN, certificate from CA is required, because I can't establish VPN connection or I can use certificate that will be generated through my server, I am not completely understand all advantage of certificate from CA, except that will be in DB of trusted certificate of phone.

Regards, Ihor.



It's equivalent operation I am right, second way only more elegant?

Not exactly equivalent as the first option looks to import the identity and then look for it in the Keychain. Note that SecPKCS12Import does not auto-import a PKCS12 into the keychain when you use it to open a PKCS12 on disk. I am betting you are having issues with the first option, correct?

I am put my certificate like local file in folder inside xcode.

I would re-examine this process because this PKCS12 does contain a private key. Typically you could load this identity via MDM or over the network.

And please clarify me about one thing, when I am build VPN, certificate from CA is required, because I can't establish VPN connection or I can use certificate that will be generated through my server

The easier course of action here is to obtain a certificate that was issued from a Certificate Authority that exists in the iOS trust store. Then use this issued certificate between your VPN server and your PKCS12.

You can install a root certificate from a In-House certificate authority but this cannot be done in your app programmatically. For example, if the code below is meant to install a Root Certificate from your In-House authority, then this will not work:

Code Block swift
let rootCertPath = Bundle.main.path(forResource: "client", ofType: "p12")
let certficiateData = NSData(contentsOfFile: rootCertPath!)
return certficiateData!


You can try to install this In-House root by hand and manually trust it on the device, or install it with MDM.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Yes you are right, I am have problem with first option), because I am decide use this example of read .p12 file https://gist.github.com/algal/66703927b8379182640a42294e5f3c0b, and I am thing it's should work right, I not tested this way on my app, but in I created another project and try read .p12 file and seems alright.
Code Block
     let urlPath = Bundle.main.url(forResource: "client", withExtension: "p12")
    let url = URL(string: urlPath!.description)
    let certData = NSData(contentsOf: url!)
    let check = PKCS12(PKCS12Data: certData!, password: "*****")
     
    print(check.self)
    print(check.label as Any)
    print(check.keyID as Any)
    print(check.identity as Any)
    print(check.certChain as Any)
    print(check.trust as Any)


And inside console I am have this output
Code Block
0
testIfCorrectDataInsidePKCS12File.PKCS12
nil
nil
Optional(<SecIdentityRef: 0x600001135800>)
Optional([<cert(0x7fc734c06ef0) s: client i: 127.0.0.1>])
Optional(<SecTrustRef: 0x600002338240>)


File client.p12, I am just put inside project like this: https://gist.github.com/IhorYachmenov/cb9343fa580eca7d503ae3dcfb7d8320

I am thing it maybe work, but I'll test it after reconfiguration server.

I am few ways how to read data from .p12
#1 from here - https://gist.github.com/algal/66703927b8379182640a42294e5f3c0b
#2 from here - https://gist.github.com/IhorYachmenov/3de282a602b72edc930c378b7ebc26bc - I am obtain result "Certificate installed Successfully" but I am don't understand what I am should write here
Code Block
let IKEv2Protocol = NEVPNProtocolIKEv2()
IKEv2Protocol.identityReference = /* How I am should load data here? */

I am think that I am missing something, I can read data from certificate these data looks like:
Code Block
[Optional(<SecIdentityRef: 0x600002e2d9c0>), Optional(<SecTrustRef: 0x600001c00090>), testIfCorrectDataInsidePKCS12File.PKCS12, Optional([<cert(0x7fb26ec07220) s: client i: 127.0.0.1>])]

but how I am should convert this Data for "identityReference", also I am saw example by eskimo https://developer.apple.com/forums/thread/68897.
To be honest, I'm a little confused). It seems to me that I am doing everything right, but I am missing something.

Also I am try use this code to read .p12 - https://gist.github.com/IhorYachmenov/4b9aca618d74c5986ece3508e77ca85d - returned value is - SecIdentity, also I can rewrite code and obtain SecCertificate but how in past to "identityReference" ?
Code Block
Optional(<cert(0x7fe380506200) s: client i: 127.0.0.1>)

but I am don't understand what I am should write here

Code Block swift
let IKEv2Protocol = NEVPNProtocolIKEv2()
IKEv2Protocol.identityReference = /* How I am should load data here? */


An identityReference here is a reference to a persistent keychain to a item containing the certificate and private key components of the tunneling protocol authentication credential. So this would be an identity not loaded from disk but referenced from the keychain.

If you continue to experience issues here feel free to open a TSI for further help.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Is it even possible load certificate(generated by my server) .p12 from disk, when I am create VPN profile programmatically or I am only should take certificate from CA which will be in TrustStore?
Option 1 :
If yes, I can use this code,
Code Block
let IKEv2Protocol = NEVPNProtocolIKEv2()
IKEv2Protocol.identityDataPassword = /*my pass*/
IKEv2Protocol.identityData = /*my .p12*/

and how I am should load file to identity data? Like this:
Code Block
let urlPath = Bundle.main.url(forResource: "client", withExtension: "p12")
let url = URL(string: urlPath!.description)
let certData = NSData(contentsOf: url!)

or I am should get particular data(SecKey, SecCertificate.... but I don't know how their convert for identityData).

About identity data I am read that

"The certificate and private key components of the tunneling protocol authentication credential, in PKCS12 format."

Option 2 :
When I am use this code I can load from disk but before, save particular data to keychain?
Code Block
let IKEv2Protocol = NEVPNProtocolIKEv2()
IKEv2Protocol.identityReference = /* How I am should load data here? */

If yes which data I am should save to keychain? From .p12 I can get:
SecKey, SecCertificate, and few others data, and how later convert to Data for identityReference?

Regards, Ihor.


or I am only should take certificate from CA which will be in TrustStore?

I would try and start with the most straight forward path first, which would be using a certificate issued from a known CA, and get that working. From there you can investigate using your own certificate. Try loading this into identityDataPassword and identityData and go from there.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Ok, I am tried this.
When I am try use this way with own certificate I am obtain this error:
Code Block
2020-10-09 22:47:02.431130+0300 Venom[2292:672763] Connection 6: received failure notification
2020-10-09 22:47:02.431406+0300 Venom[2292:672763] [connection] nw_flow_add_write_request [C6.1 127.0.0.1:000(fake ip/port) failed channel-flow (satisfied (Path is satisfied), viable, interface: en0, ipv4, dns)] cannot accept write requests
2020-10-09 22:47:02.431467+0300 Venom[2292:672763] [connection] nw_write_request_report [C6] Send failed with error "Socket is not connected"

I am use this code:
Code Block
IKEv2Protocol.identityDataPassword = self.p12Password
IKEv2Protocol.identityData = self.dataFromFile()
   func dataFromFile() -> Data? {
    let rootCertPath = Bundle.main.url(forResource: "client", withExtension: "p12")
    print(rootCertPath?.absoluteURL)
     
    return try? Data(contentsOf: rootCertPath!.absoluteURL)
  }


path to my own certificate :
Code Block
Optional("file:///private/var/containers/Bundle/Application/9E41065A-C422-4425-ACCE-BA333866C040/Venom.app/client.p12")


How I can obtain more detain info about error?

And my second question, how obtain certificate from CA, it is free or need pay and which requirements to my server? You can give me more detailed info about this process?

Regards, Ihor.

When I am try use this way with own certificate I am obtain this error:

This is a network error when trying to write to a socket that is not connected. Check your server side logs when this happens and see if your connection is even reaching it and failing with the key exchange or the VPN cannot even connect.

And my second question, how obtain certificate from CA, it is free or need pay and which requirements to my server? You can give me more detailed info about this process?

Typically you could purchase a certificate from a CA and use this between your server and you client. There may be free options as well, you will need to look. Research the CA's in the trust store and see if any of these CA's align with any previous certificate's you have obtained for work or personal reasons. Then contact that CA and either purchase or obtain a free leaf certificate.

<https://support.apple.com/en-us/HT210770>


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
From my last answer when I am obtain this error.
Code Block
2020-10-09 22:47:02.431467+0300 Venom[2292:672763] [connection] nw_write_request_report [C6] Send failed with error "Socket is not connected"

I am examine more detail server side log, and saw that I am have connection to vpn but only on few second then I am automatic disconnected but I am don't understand why? Also I am observe that when I am install file .mobileconfig on iphone his stop working after one day, and I am saw message when trying connected "Unexpected error occur", in google I am find few conversations that It's not only my problem, but not find answer(.

Example of server side log:
Code Block
Oct 12 08:49:17 server charon: 09[IKE] 195.114.147.67 is initiating an IKE_SA
Oct 12 08:49:18 server charon: 11[IKE] IKE_SA ikev2-pubkey[91] established between 168.119.152.40[168.119.152.40]...195.114.147.67[client@935bfdbd-dcba-5667-a6bc-85ffa6dcbb73.algo]
Oct 12 08:49:18 server charon: 11[IKE] CHILD_SA ikev2-pubkey{4} established with SPIs c2424671_i 07f5b8dd_o and TS 0.0.0.0/0 ::/0 === 10.19.48.1/32 2001:db8:4160::1/128
Oct 12 08:49:23 server charon: 13[IKE] deleting IKE_SA ikev2-pubkey[91] between 168.119.152.40[168.119.152.40]...195.114.147.67[client@935bfdbd-dcba-5667-a6bc-85ffa6dcbb73.algo]
Oct 12 08:49:23 server charon: 13[IKE] IKE_SA deleted
Oct 12 08:54:57 server charon: 07[IKE] 195.114.147.67 is initiating an IKE_SA
Oct 12 08:54:57 server charon: 12[IKE] 195.114.147.67 is initiating an IKE_SA
Oct 12 08:57:42 server charon: 11[IKE] 195.114.147.67 is initiating an IKE_SA
Oct 12 08:57:42 server charon: 06[IKE] 195.114.147.67 is initiating an IKE_SA
Oct 12 08:57:44 server charon: 13[IKE] 195.114.147.67 is initiating an IKE_SA
Oct 12 08:57:44 server charon: 07[IKE] 195.114.147.67 is initiating an IKE_SA


And example of my code how I am create vpn profile,
https://gist.github.com/IhorYachmenov/40de35a0256179e8a7d4f052c4ec76de
I am sure that code work well, but how examine problem and know that is not iOS problem or opposite?
Accepted Answer

I am examine more detail server side log, and saw that I am have connection to vpn but only on few second then I am automatic disconnected but I am don't understand why?

It sounds like you are getting closer on the server side. Try and track down the exact timestamp when you noticed the VPN connected and check your server logs and also the logs for your VPN in the Console.app. There should be something for you to go on here.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
You are was be right, it's closer to server side.
I am installed successful vpn profile and all work well, I am just reinstall all vpn server, and each time check server logs and try connecting to server, was need change EAP configuration and name of some preferences. This is example of my code, if anyone will be have the same problem.

https://gist.github.com/IhorYachmenov/fb63fd19f30541780950b6670e8a2865

Thank you very much Matt for help.
Regards, Ihor.
Building VPN, what to choose?
 
 
Q