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 > >