7 Replies
      Latest reply on Oct 27, 2019 6:20 AM by eskimo
      GlacierSec Level 1 Level 1 (0 points)

        We are trying to load/install an IPSEC VPN through our app, and have not yet been successful. According to Eskimo (see https://forums.developer.apple.com/thread/70696), the preferred mechanism would be NEVPNManager, with other options being hosting on an external web server, or as a last resort a web server in the app.

         

        We have a mobileconfig file from our VPN server that works if loaded manually, but have been unsuccessful using it with other mechanisms.

         

        Web Server:

        We do not have an external web server that would be a good place to host the mobileconfig files right now. However, we do have access to a cloud server data storage from which we can pull the mobileconfig file. We do use GCDWebServer in the app and spent some time trying to get that to work (ingesting and saving a mobileconfig, and then opening the URL), but we were unsuccessful in the short time that we tried. In reality, we’d rather not use that mechanism anyway because we don’t want to end up in a browser window outside of the app.

         

        NEVPNManager and Personal VPN

        We have ingested and parsed the mobileconfig file (from cloud server), setting values in NEVPNManager and NEVPNProtocolIKEv2 protocol object. But when we try to start the VPN, it is unsuccessful. Looking at console messages, it looks like the issue is related to the root CA. Some of the relevant console messages we are seeing are as follows:

         

        BACKTRACE failed to retrieve remote CA cert data by CN (xxx.xxx.xxx.xxx)

        remoteCertAuthorityArray missing from config

        Certificate authentication data could not be verified

        Failed to process IKE Auth packet (connect)

         

        Originally the VPN server was using a mobileconfig with a self-signed root cert, but then after reading Eskimo’s responses (in https://forums.developer.apple.com/thread/84679 and https://forums.developer.apple.com/thread/114575 and https://forums.developer.apple.com/thread/108004 and https://forums.developer.apple.com/thread/76227), we were able use Let’s Encrypt to issue the certificate used in the mobileconfig. And yet we still are getting the exact same result, and same messages in Console.

         

        A few additional details:

        I read in the mobileconfig file as a dictionary and pulled the cert information from PayloadContent in its section in the mobileconfig. The mobileconfig has Base64 encoded pkcs12 certificate with a password (PayloadDescription for that section says "Adds a PKCS#12-formatted certificate”). The PayloadContent is a “data” type tag, so when I get it’s value it looks like it correctly reads it into the NSData object, and so I set the following on the NEVPNProtocolIKEv2 protocol object. Does this look correct?

         

        protocol.identityDataPassword = [certDictionary valueForKey:@"Password"];
        protocol.identityData = [certDictionary valueForKey:@"PayloadContent"];

         

         

        There is also a 2nd cert section, with PayloadDescription of "Adds a CA root certificate”. There doesn’t seem to be a place for this in NEVPNManager, but I thought maybe with a valid cert, it would get that information from the VPN server?

         

        if I run something like this against the mobileconfig file:

        openssl pkcs7 -inform DER -print_certs -in test.mobileconfig > test.pem
        openssl x509 -in test.pem -noout -text

         

        It shows (along with all the other info):

         

        Issuer: O=Digital Signature Trust Co., CN=DST Root CA X3

        Subject: C=US, O=Let's Encrypt, CN=Let's Encrypt Authority X3

         

        And yet the numerous other things I’ve tried, end up showing: Issuer: CN=xxx.xxx.xxx.xxx (VPN server IP, which is also set as serverCertificateIssuerCommonName in the mobileconfig)

         

        In spite of spending quite a bit of time looking at this, I’m wondering if I’m just still ignorant about how certs work.

         

        Has anyone tried to parse the cert data out of a mobileconfig file to set up a VPN connection via NEVPNManager?

        • Re: Can I set up IKEv2 with NEVPNManager using mobileconfig data?
          eskimo Apple Staff Apple Staff (12,315 points)

          Originally the VPN server was using a mobileconfig … we were able use Let’s Encrypt to issue the certificate used in the mobileconfig.

          I don’t understand this.  The certificate for your VPN server doesn’t need to be in the configuration profile, it needs to be returned by the VPN server as part of the VPN handshake.

          So, to clarify, how many payloads are in your configuration profile?  And what are their payload types?

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"

            • Re: Can I set up IKEv2 with NEVPNManager using mobileconfig data?
              GlacierSec Level 1 Level 1 (0 points)

              Thank you for the response and sorry for the confusion. There are two payloads in the configuration file. One PayloadType is "com.apple.security.pkcs12" and one is "com.apple.security.root".

               

              We are using an AlgoVPN server that is automatically setup with a set of scripts. If I go to manually install the mobileconfig it produces with the default setup, in the details of Settings -> Profile Downloaded, it shows two certificates and shows up as "Not Signed". It looks like the root CN is just the IP address of the server.

               

              So, we updated the server to use Let's Encrypt (or at least we tried). With the updated profile, if I manually load and then look in Settings, it shows as signed and verified. In More Details it shows two certificates (similar to the default with one of them having the IP address of the server as the CN) as well as two signing certificates (related to Let's Encrypt).

               

              In https://forums.developer.apple.com/thread/84679, you mentioned that "The profile contains a custom root certificate (a payload of type com.apple.security.root).  Presumably your VPN server has a certificate issued by that custom root certificate." Our profile does have that payload type. But then you also said "If you want to continue down the NEVPNManager path you will have to get a trusted CA to issue you a certificate for your VPN server." That's what we were trying to accomplish with the updated profile. Are we still missing or misunderstanding something?

                • Re: Can I set up IKEv2 with NEVPNManager using mobileconfig data?
                  eskimo Apple Staff Apple Staff (12,315 points)

                  So, we updated the server to use Let's Encrypt (or at least we tried).

                  At this point I’d recommend that you confirm that.  I’ve yet to find a way to get the certificate list from an IPsec or IKEv2 VPN server (Anyone know of an equivalent to openssl s_client for VPN?), so my advice is that you edit your configuration profile to remove the com.apple.security.root payload.  If that works, you should be able to get Personal VPN working.

                  You can edit the profile by hand or use Apple Configurator.

                  Share and Enjoy

                  Quinn “The Eskimo!”
                  Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                  let myEmail = "eskimo" + "1" + "@apple.com"

                    • Re: Can I set up IKEv2 with NEVPNManager using mobileconfig data?
                      GlacierSec Level 1 Level 1 (0 points)

                      When you say "I’d recommend that you confirm that", how would I do that? If I run the following against the profile it shows information about Let's Encrypt, but maybe this isn't what you mean?

                       

                      openssl pkcs7 -inform DER -print_certs -in test.mobileconfig > test.pem

                      openssl x509 -in test.pem -noout -text

                       

                      I can remove the com.apple.security.root payload from the mobileconfig by hand, but I'm not sure how that helps me with NEVPNManager? I'm not actually using that section for anything in the NEVPNManager or IKEv2 parameters in code because I'm not sure where it fits. My lack of understand of certificates and chains could be causing issues here. Is there something in the pkcs12 that points to that invalid root?

                       

                      Edit: After looking at this more and talking to my co-worker about how the profile was created, I think we are not using Let's Encrypt the way that I originally thought. It seems Let's Encrypt basically just signed the profile that was created by AlgoVPN (after the fact). I think we still need to figure out how to create the profile with a valid certificate, which may be difficult with Algo since everything is automated and done by scripts. I think they use self-signed certs because it was designed to be a "personal" VPN. From a response to an issue on their github "They're self-signed...and the only person with the keys is you. This is the whole point of Algo -- you're the only one who gets to see your traffic."

                       

                      I'll try removing that root payload section, but if it helps, here's the current sample code I'm using with some things hardcoded (to values that are in the profile) and some pulled from the mobileconfig:

                       

                      Side note: Along the way I tried a bunch of things from various posts that may or may not not be useful. For instance, I "loadFromPreferencesWithCompletionHandler" and then "save" and then "load" again before trying to start the VPN because of comments on various forums.

                       

                          NSDictionary *ipdict = [NSDictionary dictionaryWithContentsOfURL:ipsecProfile];

                          NEVPNManager *manager = [NEVPNManager sharedManager];

                       

                          manager.onDemandEnabled = YES;

                          NSMutableArray *rules = [[NSMutableArray alloc] init];

                          NEOnDemandRuleConnect *connectRule = [NEOnDemandRuleConnect new];

                          NEOnDemandRuleDisconnect *disconnectRule = [NEOnDemandRuleDisconnect new];

                          [rules addObject:connectRule];

                          [rules addObject:disconnectRule];

                       

                          NEVPNProtocolIKEv2 *protocol = [[NEVPNProtocolIKEv2 alloc] init];

                          protocol.authenticationMethod = NEVPNIKEAuthenticationMethodCertificate;

                       

                          protocol.childSecurityAssociationParameters.diffieHellmanGroup = NEVPNIKEv2DiffieHellmanGroup20;

                          protocol.childSecurityAssociationParameters.encryptionAlgorithm = NEVPNIKEv2EncryptionAlgorithmAES256GCM;

                          protocol.childSecurityAssociationParameters.integrityAlgorithm = NEVPNIKEv2IntegrityAlgorithmSHA512;

                          protocol.childSecurityAssociationParameters.lifetimeMinutes = 1440;

                       

                          protocol.deadPeerDetectionRate = NEVPNIKEv2DeadPeerDetectionRateMedium;

                          protocol.disableMOBIKE = NO;

                          protocol.disableRedirect = YES;

                          protocol.enableRevocationCheck = NO;

                          protocol.enablePFS = YES;

                       

                          protocol.IKESecurityAssociationParameters.diffieHellmanGroup = NEVPNIKEv2DiffieHellmanGroup20;

                          protocol.IKESecurityAssociationParameters.encryptionAlgorithm = NEVPNIKEv2EncryptionAlgorithmAES256GCM;

                          protocol.IKESecurityAssociationParameters.integrityAlgorithm = NEVPNIKEv2IntegrityAlgorithmSHA512;

                          protocol.IKESecurityAssociationParameters.lifetimeMinutes = 1440;

                       

                          NSArray *parray = [ipdict objectForKey:@"PayloadContent"];

                          NSDictionary *pcontent = parray[0];

                          NSDictionary *pcontent2 = parray[1];

                          protocol.localIdentifier = [pcontent valueForKeyPath:@"IKEv2.LocalIdentifier"];

                          protocol.certificateType = NEVPNIKEv2CertificateTypeECDSA384;

                          protocol.serverCertificateIssuerCommonName = [pcontent valueForKeyPath:@"IKEv2.ServerCertificateIssuerCommonName"];

                          protocol.serverAddress = [pcontent valueForKeyPath:@"IKEv2.RemoteAddress"];

                          protocol.remoteIdentifier = [pcontent valueForKeyPath:@"IKEv2.RemoteIdentifier"];

                          protocol.useConfigurationAttributeInternalIPSubnet = NO;

                       

                          protocol.proxySettings.HTTPEnabled = NO;

                          protocol.proxySettings.HTTPSEnabled = NO;

                          protocol.username = [pcontent valueForKeyPath:@"UserDefinedName"];

                       

                          protocol.identityDataPassword = [pcontent2 valueForKey:@"Password"];

                          protocol.identityData = [pcontent2 valueForKey:@"PayloadContent"];

                       

                          protocol.useExtendedAuthentication = NO;

                          protocol.disconnectOnSleep = NO;

                       

                          [manager loadFromPreferencesWithCompletionHandler:^(NSError *error) {

                              if(error) {

                                  DDLogInfo(@"IPSEC loadFromPreferencesWithCompletionHandler error: %@", error.localizedDescription);

                                  return;

                              }

                              manager.onDemandEnabled = YES;

                              [manager setOnDemandRules:rules];

                              manager.protocolConfiguration = protocol;

                              [manager setLocalizedDescription:@"IPSEC VPN"];

                              [manager saveToPreferencesWithCompletionHandler:^(NSError *error) {

                                  if(error) {

                                      DDLogInfo(@"IPSEC saveToPreferencesWithCompletionHandler error: %@", error.localizedDescription);

                                      return;

                                  }

                       

                                  [manager loadFromPreferencesWithCompletionHandler:^(NSError *error) {

                                      if(error) {

                                          DDLogInfo(@"IPSEC loadFromPreferencesWithCompletionHandler2 error: %@", error.localizedDescription);

                                          return;

                                      }

                           

                                      NSError *startError;

                                      [manager.connection startVPNTunnelAndReturnError:&startError];

                                      if(startError) {

                                          DDLogInfo(@"IPSEC Start error: %@", startError.localizedDescription);

                                      }

                                  }];

                              }];

                          }];

                        • Re: Can I set up IKEv2 with NEVPNManager using mobileconfig data?
                          eskimo Apple Staff Apple Staff (12,315 points)

                          When you say "I’d recommend that you confirm that", how would I do that?

                          1. Remove the com.apple.security.root payload from your configuration profile.

                          2. Install it.

                          3. Does it work?

                          If it doesn’t work, you won’t be able to get Personal VPN to work because NEVPNManager offers a strict subset of what you can do in a configuration profile.  If it does work, you can probably get Personal VPN to work, it’s just a question of using it in exactly the right way (it is, in my experience, a rather persnickety API).

                          Share and Enjoy

                          Quinn “The Eskimo!”
                          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                          let myEmail = "eskimo" + "1" + "@apple.com"