Ted,

Thank you for sending this - I’m sure it will be useful to someone, and now 
it’s “archived” for those who go looking for help in the future.

-David

> On Apr 2, 2021, at 3:41 PM, Theodore Wynnychenko <t...@uchicago.edu> wrote:
> 
> Hi
> I had some time today, and decided to send this now.
> 
> This is how I got OpenBSD's iked daemon (version in current about 3/28/2021)
> to work with Apple's iOS (iphone/ipad's) version (about) 14.4.2.
> 
> Some prelude:
> 
> So, I have no real reason to do this, other than that I want to.
> I think of it as a learning exercise, so my knowledge is limited in many
> ways.  I got this to work for my specific use case.
> 
> Specially, I only have a few devices that I want/need to have access to my
> home's VPN.  I do this to have a secure gateway for access to my
> email/calendar/files/etc when not at home (yes, I host my own services - I
> know that Apple and Google and other respect my privacy, etc., but ...).
> 
> I have NOT tried to set this up as a VPN to route all traffic from
> associated devices (I don't have the a connection with the bandwidth
> necessary to do so).
> 
> Because I am only "managing" a handful of devices, I did all of this
> manually.
> 
> 
> Limitations/Requirements:
> 
> Apple's iOS:
> 
> Recently, Apple has put several restrictions on the certificates iOS devices
> will accept for ikev2 connections.  These are "disclosed" at
> https://support.apple.com/en-us/HT211025 and
> https://support.apple.com/en-us/HT210176.
> 
> Specifically, certificates must:
> - CA and TLS certs using RSA must use key => 2048
> - CA and TLS certs must use SHA-2
> - TLS certs must have a SubjectAlternativeName with the DNS name of the
> server; a CommonName only is not enough
> 
> For certificates issued after 7/1/2019:
> - ExtendedKeyUsage for TLS server and TLS client must be included
> - TLS certs can only be valid for 825 days or less
> 
> For certificates issued by the Root CA's preinstalled in iOS, after
> 9/1/2020:
> - TLS certs can only be valid for 398 days or less
> 
> 
> 
> OpenBSD's iked:
> 
> OpenBSD ikev2 also has some specific requirements for certificate
> authentication.
> 
> iked requires specific key/authentication combinations:
> - rfc7427 only supports SHA2-256 (not sure if iOS supports rfc7427)
> - ecdsa256 only supports P-256 with SHA2-256
> - ecdsa382 only supports P-384 with SHA2-384
> - ecdsa521 only supports P-521 with SHA2-512
> - rsa suppors RSA but only with SHA1
> 
> 
> Other/General:
> 
> In terms of ECDSA certificates, it seems that P-256 and P-384 are the ones
> that are more generally accepted, and will likely continue to be generally
> accepted.  This appears to be based on NIST's inclusion of them in their
> "Suite B Cryptography" information.  P-521 was not included in "Suite B,"
> and it seems some things have not included support for it.
> 
> So, I concluded, to be safe (and since it seems the computational/security
> cost/benefit of P-384 vs P-521 is narrow), and based on the requirements
> above, to use P-384 with SHA2-384.
> 
> 
> My setup:
> 
> Certificates:
> 
> In order to do this, I used openssl commands directly.  I did not use ikectl
> to create certs or the CA.
> 
> Before I go into details, I wanted to have certs that would last longer than
> the Apple limit.  Therefore, I needed to have a CA certificate, and TLS
> certs, that had a "Not Before" date before 7/1/2019.
> 
> In order to do this, when I created my CA certificate, I changed the
> time/date on the system using "date 201901010000" before creating the CA,
> and then reset the date when I was done.
> 
> Creating back-dated TLS certs is a bit more direct, all that is necessary is
> to add "-startdate 20190102000000Z" to the openssl ca command when signing
> the TLS certificate.
> 
> Obviously, you need to have complete control of the CA (and not care that
> you are doing this) to accomplish this and get certificates with a longer
> time horizon for iOS.
> 
> So, first I created a CA using ECDSA384:
> 
> I created/edited the openssl.cnf file to have the appropriate
> additions/defaults I need for these certificates.  I will not cover
> everything, but I think these are the basic requirements (I have edited out
> many things in the actual file I used, but I THINK what is left is all that
> may be really needed, but my openssl knowledge is not absolute, and I may
> have errors that I don't realize):
> 
> (NOTE:  When I was trying to get this to work, I began to believe that the
> current iOS has a problem with "-" [hyphens] in the CN/SAN, so I did not use
> them.  I now am not sure if "-"'s will work or not.]
> 
> General defaults for generating the signing request (csr), openssl.cnf:
> 
> default_bits        = 4096
> default_keyfile    = key.pem    
> default_md        = sha384
> string_mask        = utf8only
> distinguished_name    = req_distinguished_name
> attributes        = req_attributes
> 
> The distinguished name/attributes are basically from the default cnf file.
> 
> For the CA cert, openssl.cnf:
> 
> basicConstraints        = CA:TRUE
> subjectKeyIdentifier    = hash
> authorityKeyIdentifier    = keyid:always,issuer:always
> issuerAltName            = issuer:copy
> 
> For the TLS certs, when creating the signing request, openssl.cnf:
> 
> basicConstraints        = CA:FALSE
> subjectKeyIdentifier    = hash
> authorityKeyIdentifier    = keyid:always,issuer:always
> subjectAltName            = email:move
> 
> For the TLS certs, when signing with CA, openssl.cnf:
> 
> default_days        = 390 # Most restrictive days for iOS
> default_md        = sha384
> preserve            = no
> email_in_dn        = no
> policy            = policy_match
> copy_extensions    = copy
> extendedKeyUsage    = serverAuth,clientAuth
> subjectAltName        = DNS:same.as.CN,email:n...@domain.tld
> 
> 
> In the steps that follow, the openssl.cnf file will need to be adjusted to
> match each certificate (both CA and TLS) as they are created.
> 
> Create a CA key - I did this in two steps here, later only one:
> 
> openssl ecparam -name secp384r1 -out secp384r1.param
> 
> openssl ecparam -in secp384r1.param -genkey -out ca.ecdsa.key.nopass
> 
> I wanted a password for the CA key, so,
> 
> openssl ec -aes256 -in ca.ecdsa.key.clear -out ca.ecdsa.key.pem
> 
> and then deleted the unencrypted key.
> 
> Then, create the CA self-signed certificate:
> 
> openssl req -new -x509 -key ca.ecdsa.key.pem -out cacert.pem -days ###
> -config openssl.cnf
> 
> Now, there is a CA certificate and key with ECDSA384 and SHA2-384.
> 
> Create the TLS server cert and key (only one step this time):
> 
> openssl ecparam -genkey -name secp384r1 -out server.key
> 
> Make the csr:
> 
> openssl req -nodes -new -key ikev2.key -out server.csr -config openssl.cnf
> 
> Sign the csr with the CA:
> 
> openssl ca -in server.csr -out server.pem -config openssl.cnf
> 
> 
> Now, create a client cert the same way, but one extra step.
> First, create the key, create the CSR, and sign it to get the certificate.
> 
> But, this has to be bundled in to a .p12 file for import to iOS:
> 
> openssl pkcs12 -export -in client.pem -inkey client.key -CAfile cacert.pem
> -out client.p12
> 
> 
> Now, there is a cacert.pem (the CA certificate), a server.pem and server.key
> (the iked daemon's certificates), and a .p12 with the iOS client's
> certificate and key, and the ca certificate (even though I also import the
> cacert directly into iOS as a der file).
> 
> Move the cacert.pem, server.pem, and server.key into the appropriate places
> for iked to find them.
> 
> 
> 
> Setup IKED:
> 
> If I recall, the PF setup I use just basically follows the guidance in the
> man page (I did this years ago).
> 
> In my case, it looks like this:
> 
> pass in  on $ext_if proto udp from any to $ext.ip port { isakmp, ipsec-nat-t
> }
> pass out on $ext_if proto udp from $ext.ip to any port { isakmp, ipsec-nat-t
> }
> pass in  on $ext_if proto udp from any to $local_net port { isakmp,
> ipsec-nat-t }
> pass out on $ext_if proto udp from $local_net to any port { isakmp,
> ipsec-nat-t }
> 
> pass in  on $ext_if proto esp from any to $ext.ip
> pass out on $ext_if proto esp from $ext.ip to any
> 
> pass in  on enc0 proto ipencap from any to $ext.ip keep state (if-bound)
> pass out on enc0 proto ipencap from $ext.ip to any keep state (if-bound)
> 
> pass in  on enc0 from <ip_ assigned_by_iked> to any keep state (if-bound)
> pass out on enc0 from any to < ip_ assigned_by_iked > keep state (if-bound)
> 
> 
> I don't use NAT, since I only have a handful of devices, and each gets
> assigned a unique IP address by iked.
> 
> 
> Each device has its own specific entry in iked, and they look like this:
> 
> ikev2 "client_1" passive esp \
>        from $local_net to $vpn_net \
>        local $local_gw peer any \
>        srcid $server_id dstid $client_id \
>        ikelifetime 30m lifetime 30m \
>        ecdsa384 \
>        config address aaa.bbb.ccc.ddd \
>        config netmask 255.255.255.0 \
>        config name-server aaa.bbb.ccc.111 \
>        config name-server aaa.bbb.ccc.222
> 
> 
> local_net = my internal network block
> vpn_net = network block assigned by iked to clients
> local_gw = FQDN of local endpoint
> server_id = CN/SAN of server as listed in certificate created
> client_id = CN/SAN of client as listed in certificate created
> 
> I use iked to give each client a specific and unique IP address, and they
> all fall into the "vpn_net" netblock.
> 
> I also "config" DNS servers.  But, I don't think iOS accepts these (as I
> will get to later), but I never bothered removing them to see if it would
> still work.
> 
> So, each client has a policy in iked that matches the CN/SAN in its
> certificate, and iked also uses the CN/SAN of the server as the srcid for
> the policy.
> 
> 
> Finally, setting up the iOS client:
> 
> In order to do this I use profiles that get imported in the iOS device.
> 
> The profiles are generated by Apple Configurator 2 (which requires a Mac),
> but then also edited them directly (I will explain why later).
> 
> I guess you don't really need the Apple software, as all AC2 does is
> generate an XML file.  All the parameters in AC2 (and others that are not
> available in AC2) are published by Apple in the "Configuration Profile
> Reference."  So, I guess this could be created by hand, but I choose not to.
> 
> (I am not looking at the AC2 pages as I type this, so if I make a slight
> misstatement, sorry.)
> 
> To create the profile, there are three sections to complete.
> 
> First, I filled out the mandatory General tab.
> 
> In the Certificates tab, I added the cacert.der (I converted the .pem to a
> .der for Apple, but I think it would accept the .pem if you change the file
> extension to .crt - maybe?) to the profile.
> 
> I then added the client.p12 to the profile, also entering the password given
> to the .p12 when creating it.
> 
> Finally, in the VPN tab, I set up the ikev2 parameters.
> 
> Specially:
> 
> Connection Type: IKEv2
> Server:  FQDN of my server
> Remote Identifier:  the CN/SAN from the server certificate
> Local Identifier:  the CN/SAN from the client certificate
> Machine Authentication:  Certificate
> Identity Certificate:  choose the certificate you added
> Certificate type:  ECDSA384
> Server certificate issuer common name:  CA certificate CN
> 
> ***** THIS IS REQUIRED *****
> ***** EVEN THOUGH AC2 LISTS THIS FIELD AS ONLY REQUIRED FOR EAP, THE
> REFERENCE GUIDE SPECIFICALLY STATES THAT IT IS REQUIRED WHEN A CERTIFICATE
> TYPE IS SELECTED (This was the last thing I changed before getting it to
> work - without this set, iOS gives a cryptic "User authentication failed"
> error and will not connect, while AT THE SAME TIME, IKED shows the
> connection state changing to VALID and waits for additional traffic - This
> was very frustrating.) *****
> 
> Server Certificate common name:  "optional," but is it really (see above),
> so I entered the TLS certificate's CN/SAN explicitly here
> 
> Enable EAP:  NOT SELECTED
> Disconnect on Idle:  NEVER
> Dead peer detection rate:  HIGH
> Disable redirects:  NOT SELECTED
> Disable Mobility (MOBIKE):  SELECTED
> Use IP4/IP6 Subnet attributes:  SELECTED
> Enable PFS:  NOT SELECTED
> Enable Cert Revoke check:  NOT SELECTED
> 
> 
> For both IKE SA and child SA parameters, I used:
> AES-256
> SHA2-384
> DH Group 20
> ***** I ONLY SELECTED THESE SETTINGS HERE *****
> ***** When I tried to set arguments for this in iked.conf, the connection
> would not work, so I did not set ANY specifics for the connection in
> iked.conf *****
> 
> Proxy Server URL:  None
> 
> --------------------
> 
> Now, in my situation I also added information for DNS servers and a VPN on
> demand setup.
> 
> Years ago, the DNS settings had to be done by hand to the xml file, but now
> they are included in AC2.  I need this because the iOS client needs to
> direct any DNS queries for my personal domain to internal DNS servers over
> the tunnel.  Without setting the DNS in the profile, a VPN connection comes
> up, but, unless everything on the iOS device is set with IP address, the
> internal FQDN's will not resolve using public DNS servers.
> 
> So, in my case, in AC2, I added:
> 
> DNS Server Addresses:  internal IP's of my DNS servers
> Domain Name:  mypersonaldn.tld
> DNS Search Domains:  mypersonaldn.tld
> DNS Supplemental Match Domains:  mypersonaldn.tld
> Include Supplemental Domains...:  SELECTED
> 
> These settings direct iOS to send DNS queries for my personal domain through
> the tunnel to my internal DNS servers for resolution.
> 
> 
> In my case, the VPN is only used for traffic to my internal services, and
> all other traffic on the iOS device is routed directly by it to whatever
> gateway the device is connected to at the time.
> 
> 
> Finally, I wanted to VPN connection to come up automatically when trying to
> check (for example) email (the VPN is not "always on").
> 
> So, this requires a direct editing of the .mobileconfig xml file.
> 
> In my case, I added "OnDemand" settings to the "IKEv2" dictionary.
> The Apple Reference describes the options for this.
> 
> For my situation, I added the following (I don't necessarily remember all
> the reasons of exactly why I did it like this):
> 
> <key>OnDemandEnabled</key>
> <integer>1</integer>
> <key>OnDemandRules</key>
> <array>
>    <dict>
>        <key>Action</key>
>        <string>Disconnect</string>
>        <key>SSIDMatch</key>
>        <array>
>            <string>PersonalSSID1</string>
>            <string>PersonalSSID2</string>
>        </array>
>    </dict>
>    <dict>
>        <key>Action</key>
>        <string>EvaluateConnection</string>
>        <key>ActionParameters</key>
>        <array>
>            <dict>
> <key>DomainAction</key>
> <string>ConnectIfNeeded</string>
> <key>Domains</key>
> <array>
>    <string> mypersonaldn.tld</string>
>    <string>*. mypersonaldn.tld</string>
>    <string>*.sub. mypersonaldn.tld</string>
> </array>
> <key>RequiredDNSServers</key>
> <array>
>    <string>aaa.bbb.ccc.dd1</string>
>    <string>aaa.bbb.ccc.dd2</string>
> </array>
>            </dict>
>        </array>
>    </dict>
>    <dict>
>        <key>Action</key>
>        <string>Connect</string>
>    </dict>
> </array>
> 
> 
> This addition keeps the VPN from starting when I am at home and connected
> directly to an AP with a specific SSID.  But, when not connected to that AP,
> any time a request is made for a location in my domain, the VPN comes up
> automatically.
> 
> 
> And that's it.
> I now have iOS devices running the current iOS (14.whatever) that will
> automatically connect to the -current OpenBSD iked daemon and bring up a VPN
> to my home network whenever I decide to check email (or other things).
> 
> I also backdated my CA and other certs, so I am not limited by Apple's
> certificate time constraints (in my situation, I see no problem with certs
> that are valid for more than 3 years - after all, if a family member looses
> a phone, I just delete that entry from iked.conf, and who cares how long the
> certificate is valid, I am more unhappy about the lost phone).
> 
> 
> I know this has been a long email.
> I hope that this helps someone.
> If there is something that needs to be clarified or explained better, please
> let me know, and I will try to explain better.
> 
> Ted
> 
> 

Reply via email to