Project

General

Profile

IKEv2 Configuration Profile for Apple iOS 8 and newer

While iOS 8 introduced native IKEv2 support, the VPN application's GUI was not updated to allow configuration of such connections on the devices themselves. Therefore, it was required to create IKEv2 connections with custom configuration profiles.

Since iOS 9 IKEv2 connections may be configured in the GUI. But it is still possible to configure VPN connections with profiles.

Such profiles can be created manually or you can use Apple Configurator (only runs on Mac OS X), which provides support for IKEv2 in the latest releases.

You can adjust the following templates to your setup and then send it to your device(s) via email or provide it via HTTP. In order for the iOS mail client to install the profile, the file name of the attachment must end in .mobileconfig and the content type should be application/octet-stream (Thunderbird seems to use text/html, which will not work).

Several notes to the configuration keys are provided as comments in the template files below, the official documentation can be found at developer.apple.com.

Mac OS X 10.11 and newer support IKEv2. Earlier versions only support IKEv1.

Known Issues

  • ASN.1 Distinguished Names can't be used as identities because the client currently sends them as identities of type FQDN.
  • If EAP authentication is used a username has to be configured in the profile, there is no prompt during installation (or later) if it is not set. The password is optional though, if it is not set in the profile it can be entered during installation. This has been fixed with iOS 9.
  • The client requests a virtual IPv6 address and sends IPv6 traffic selectors. Unfortunately, these selectors are invalid. The end address is sent as 00ff:00ff:00ff:00ff:00ff:00ff:00ff:00ff instead of ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff. So IPv6 can't really be used and if the responder can't handle such a proposal (like e.g. Windows Server) the connection will fail altogether (it seems not possible to disable IPv6 on the client via configuration profile). This has been fixed with iOS 8.3.

Authentication options

The client and server authentication is determined by the following options (more details can be found in comments in the templates below):

  • AuthenticationMethod = Certificate

    In all these variants the server is authenticated with a certificate. The ServerCertificateIssuerCommonName and ServerCertificateCommonName options are used to verify the server certificate.

  • AuthenticationMethod = SharedSecret

    Uses PSK authentication for client and server. The PSK can be configured with the SharedSecret option.

EAP authentication (base template)

This configuration is compatible to the Windows 7 EAP server configuration.

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <!-- Set the name to whatever you like, it is used in the profile list on the device -->
    <key>PayloadDisplayName</key>
    <string>Profile name</string>
    <!-- This is a reverse-DNS style unique identifier used to detect duplicate profiles -->
    <key>PayloadIdentifier</key>
    <string>org.example.vpn1</string>
    <!-- A globally unique identifier, use uuidgen on Linux/Mac OS X to generate it -->
    <key>PayloadUUID</key>
    <string>9f93912b-5fd2-4455-99fd-13b9a47b4581</string>
    <key>PayloadType</key>
    <string>Configuration</string>
    <key>PayloadVersion</key>
    <integer>1</integer>
    <key>PayloadContent</key>
    <array>
        <!-- It is possible to add multiple VPN payloads with different identifiers/UUIDs and names -->
        <dict>
            <!-- This is an extension of the identifier given above -->
            <key>PayloadIdentifier</key>
            <string>org.example.vpn1.conf1</string>
            <!-- A globally unique identifier for this payload -->
            <key>PayloadUUID</key>
            <string>29e4456d-3f03-4f15-b46f-4225d89465b7</string>
            <key>PayloadType</key>
            <string>com.apple.vpn.managed</string>
            <key>PayloadVersion</key>
            <integer>1</integer>
            <!-- This is the name of the VPN connection as seen in the VPN application later -->
            <key>UserDefinedName</key>
            <string>VPN Name</string>
            <key>VPNType</key>
            <string>IKEv2</string>
            <key>IKEv2</key>
            <dict>
                <!-- Hostname or IP address of the VPN server -->
                <key>RemoteAddress</key>
                <string>vpn.example.org</string>
                <!-- Remote identity, can be a FQDN, a userFQDN, an IP or (theoretically) a certificate's subject DN. Can't be empty.
                     IMPORTANT: DNs are currently not handled correctly, they are always sent as identities of type FQDN -->
                <key>RemoteIdentifier</key>
                <string>vpn.example.org</string>
                <!-- Local IKE identity, same restrictions as above. If it is empty the client's IP address will be used -->
                <key>LocalIdentifier</key>
                <string></string>
                <!-- Optional, if it matches the CN of the root CA certificate (not the full subject DN) a certificate request will be sent
                     NOTE: If this is not configured make sure to configure leftsendcert=always on the server, otherwise it won't send its certificate -->
                <key>ServerCertificateIssuerCommonName</key>
                <string>Example Root CA</string>
                <!-- Optional, the CN or one of the subjectAltNames of the server certificate to verify it, if not set RemoteIdentifier will be used -->
                <key>ServerCertificateCommonName</key>
                <string>vpn.example.org</string>
                <!-- The server is authenticated using a certificate -->
                <key>AuthenticationMethod</key>
                <string>Certificate</string>
                <!-- The client uses EAP to authenticate -->
                <key>ExtendedAuthEnabled</key>
                <integer>1</integer>
                <!-- User name for EAP authentication. Since iOS 9 this is optional, the user is prompted when the profile is installed -->
                <key>AuthName</key>
                <string>User</string>
                <!-- Optional password for EAP authentication, if it is not set the user is prompted when the profile is installed
                <key>AuthPassword</key>
                <string>...</string>
                -->
                <!-- The next two dictionaries are optional (as are the keys in them), but it is recommended to specify them as the default is to use 3DES.
                     IMPORTANT: Because only one proposal is sent (even if nothing is configured here) it must match the server configuration -->
                <key>IKESecurityAssociationParameters</key>
                <dict>
                    <key>EncryptionAlgorithm</key>
                    <string>AES-128</string>
                    <key>IntegrityAlgorithm</key>
                    <string>SHA1-96</string>
                    <key>DiffieHellmanGroup</key>
                    <integer>14</integer>
                </dict>
                <key>ChildSecurityAssociationParameters</key>
                <dict>
                    <key>EncryptionAlgorithm</key>
                    <string>AES-128</string>
                    <key>IntegrityAlgorithm</key>
                    <string>SHA1-96</string>
                    <key>DiffieHellmanGroup</key>
                    <integer>14</integer>
                </dict>
            </dict>
        </dict>
        <!-- This payload is optional but it provides an easy way to install the CA certificate together with the configuration -->
        <dict>
            <key>PayloadIdentifier</key>
            <string>org.example.ca</string>
            <key>PayloadUUID</key>
            <string>64988b2c-33e0-4adf-a432-6fbcae543408</string>
            <key>PayloadType</key>
            <string>com.apple.security.root</string>
            <key>PayloadVersion</key>
            <integer>1</integer>
            <!-- This is the Base64 (PEM) encoded CA certificate -->
            <key>PayloadContent</key>
            <data>
            MIIDajCCA...
            </data>
        </dict>
    </array>
</dict>
</plist>

Certificate authentication

This configuration is compatible to the Windows 7 machine certificate server configuration.

Only the differences to the above configuration are shown.

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    ...
    <array>
        <dict>
            ...
            <key>IKEv2</key>
            <dict>
                ...
                <!-- Local IKE identity, should match one of the subjectAltNames of the client certificate
                     IMPORTANT: As mentioned above, subject DN's currently can't be used -->
                <key>LocalIdentifier</key>
                <string>client@example.org</string>
                ...
                <!-- Either set this to 0 or don't configure it at all to use certificate authentication also for the client
                <key>ExtendedAuthEnabled</key>
                <integer>0</integer>
                -->
                <!-- Similarly, instead of AuthName and AuthPassword, we configure the certificate to use -->
                <key>PayloadCertificateUUID</key>
                <string>d60488c6-328e-4944-9c8d-61db8095c864</string>
                ...
            </dict>
        </dict>
        <dict>
            <key>PayloadIdentifier</key>
            <string>org.example.vpn1.client</string>
            <key>PayloadUUID</key>
            <string>d60488c6-328e-4944-9c8d-61db8095c864</string>
            <key>PayloadType</key>
            <string>com.apple.security.pkcs12</string>
            <key>PayloadVersion</key>
            <integer>1</integer>
            <!-- Optional password to decrypt the PKCS#12 container, if not set the user is prompted when installing the profile
            <key>Password</key>
            <string>...</string>
            -->
            <!-- This is the Base64 encoded PKCS#12 container with the certificate and private key for the client.
                 IMPORTANT: The CA certificate will not be extracted from the container, so either install it separately or include it as payload (as seen above) -->
            <key>PayloadContent</key>
            <data>
            MIINCQ...
            </data>
        </dict>
        <!-- As mentioned above the CA certificate is not extracted from the PKCS#12 container, so install it using this payload -->
        <dict>
            <key>PayloadIdentifier</key>
            <string>org.example.ca</string>
            ...
        </dict>
    </array>
</dict>
</plist>

EAP-TLS authentication

This configuration is compatible to the Windows 7 user certificate server configuration.

This is basically the same as the certificate configuration above, but with ExtendedAuthEnabled activated.

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    ...
    <array>
        <dict>
            ...
            <key>IKEv2</key>
            <dict>
                ...
                <!-- Enable EAP, by configuring PayloadCertificateUUID EAP-TLS gets used -->
                <key>ExtendedAuthEnabled</key>
                <integer>1</integer>
                <!-- Instead of AuthName and AuthPassword, we configure the certificate to use -->
                <key>PayloadCertificateUUID</key>
                <string>d60488c6-328e-4944-9c8d-61db8095c864</string>
                ...
            </dict>
        </dict>
        <!-- Certificates are configured as shown above. If your AAA server certificate is issued by a different CA just install multiple CA certificates -->
    </array>
</dict>
</plist>

Pre-shared key (PSK) authentication

Is is also possible to use PSKs for authentication.

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    ...
    <array>
        <dict>
            ...
            <key>IKEv2</key>
            <dict>
                ...
                <!-- Use a pre-shared secret for authentication -->
                <key>AuthenticationMethod</key>
                <string>SharedSecret</string>
                <!-- The actual secret -->
                <key>SharedSecret</key>
                <string>...</string>
                <!-- No EAP -->
                <key>ExtendedAuthEnabled</key>
                <integer>0</integer>
                ...
            </dict>
        </dict>
    </array>
</dict>
</plist>

Enable On-Demand VPN

It is possible to automatically trigger an VPN-Connect if needed. This example show rules, which will disconnect the tunnel when connected to a specific WiFi SSID (MySSID) and establishes a tunnel when domain name resolution of specific domains fail (*.internal.mydomain.com).
For more details have a look at Apples Configuration Profile Reference

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    ...
    <array>
        <dict>
            ...
            <key>IKEv2</key>
            <dict>
                ...
                <key>OnDemandEnabled</key>
                <integer>1</integer>
                <key>OnDemandRules</key>
                <array>
                    <!-- 
                         1. Check if we are connected to a WiFi network
                         2. Check if the SSID is included in the SSIDMatch-array
                         3. If 1 + 2 are true, then disconnect the tunnel
                    -->
                    <dict>
                        <key>InterfaceTypeMatch</key>
                        <string>WiFi</string>
                        <key>SSIDMatch</key>
                        <array>
                            <string>MySSID</string>
                        </array>                    
                        <key>Action</key>
                        <string>Disconnect</string>
                    </dict>
                    <!-- 
                         1. For each connection attempt, test if the domain name is included in the Domains-array
                         2. If 1 is true, try domain name resolution
                         3. If 2 fails or times out, establish a VPN connection
                    -->
                    <dict>
                        <key>Action</key>
                        <string>EvaluateConnection</string>
                        <key>ActionParameters</key>
                        <array>
                            <dict>
                                <key>Domains</key>
                                <array>
                                    <string>*.internal.mydomain.com</string>
                                </array>    
                                <key>DomainAction</key>
                                <string>ConnectIfNeeded</string>
                            </dict>
                        </array>
                    </dict>
                    <!-- 
                        Default entry, ignore any other cases
                    -->
                    <dict>
                        <key>Action</key>
                        <string>Ignore</string>
                    </dict>
                </array>
                ...
            </dict>
        </dict>
    </array>
</dict>
</plist>