Apple care about users privacy and security quite well. Of course it’s a matter of opinion but Apple put strong focus on encryption and peer authentication. In 2015 Apple introduced App Transport Security (ATS) as part of their Network Framework With every release they are putting more and more responsibility on developers and content operators to provide proper traffic encryption proper certificate signing and chain etc. That means if application is trying to connect to HTTP server that does not support latest TLSv1.2 connection should fail.
There is no doubt that ATS is good for end users and that’s right direction every corporation should follow. But switching to TLSv1.2 is not something that can be done just like that, obtaining signed certificate expensive option, especially for development environments or if you are writing apps to just test something or for fun. Self-signed certificates are the solution for such cases but there are few problems that we can encounter.
Major problems I faced were not with TLSv1.2 but certificate chain that is verified when connection is established. Creating self-signed certificate can be done from command line or from ASDM but it does not provide sufficient verification for Apple products to let you connect.
This post base on macOS 10.12.2 and iOS 10.2.
ATS and self-signed certificates
If you are developing an application which have to use connection to service that does not support TLSv1.2 or strong encryption you can make exception for particular host or domain or disable ATS for whole application. I’ll talk later how you do that. All discussions on developers forums or even Apple developers board focus on handshake problems, self-signed certificates etc. but none really said that even self-signed certificate or signed by own self-signed CA require certificate to contain two very important fields – CN and FQDN values. As mentioned in my previous post (How to act as your own local CA and sign certificate request from ASA) first one should contain all names that might be assigned to firewall, usually it’s limited to just hostname and FQDN record, but we also have to include the FQDN field of firewall that will be used in URLs inside of our application. If FQDN field in certificate is missing we will see following error message even if full signing path is correct and all certificates are trusted.
2017-01-14 23:16:44.485 ASAManagement[21917:24560543] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9843) The certificate for this server is invalid. You might be connecting to a server that is pretending to be “asav-1.virl.lan” which could put your confidential information at risk.
The key information here is “(kCFStreamErrorDomainSSL, -9843)”, error number 9843 code name is “errSSLHostNameMismatch” which meanst that URL application tries to open is not matching FQDN in certificate in the field is missing. That’s why we need to be careful how the certificate request is created.
Importing certificates to Apple devices
Usually if you develop an application on daily basis you run it in XCode Simulator because it can provide you emulation of all macOS, iOS or tvOS platforms. I found out that best way is to import all three (CA, Signing CA and device specific) certificates to both XCode Simulator and macOS itself otherwise you may experience errors.
Importing certificates to XCode Simulator is easy – run Simulator and then drag-and-drop certificate file into the Simulator window. System will ask you if you want to import potentially untrusted or self-signed certificate which we need to approve. On macOS we import certificates using KeyChain Access. When you look at properties of imported certificate you will see that CA is not trusted by system. That’s expected because it’s self-signed by us, we need to manually set it as trusted for at least one property, usually the SSL one, as “Always Trust”. Now as our CA is trusted by system also all certificates in hierarchy signed by our CA should be trusted. But it’s always best to manually set SSL as “Always Trusted” to device certificate to avoid problems.
When you install your application on your iPhone or IPad you also have to import certificates there. Because you can’t drag-and-drop here two easiest ways to import them are either by opening mail with certificates attached or browse to URL, where particular certificate is available, using Safari. No matter which way we choose installation process is the same as in XCode Simulator.
Bypassing ATS in XCode project
Each project has attached property list that control application behavior. You will find many discussions on StackOverflow or Apple Developers describing what need to be set and when in different XCode versions. The easiest would be disabling ATS in general for whole application
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
Node: This code need to very good justification if we want to send such application to Apple Store, it shouldn’t be used in general as it disabling all security features that are there to protect end users and their data.
Other possibility is to set several flags per domain, in my case following are required to make application work
<key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>apple.ninja</key> <dict> <key>NSIncludesSubdomains</key> <true/> <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key> <true/> </dict> </dict> </dict>
You must use FQDN as key value, IP address will be ignored. This is much safer but still you risk your application won’t be approved into Apple Store. Please refer to Apple documentation where under NSAppTransportSecurity section all parameters are explained
If you are Apple programmer or just want to write some code for fun, like I did, please remember that ATS as well as whole Network Stack Framework is evolving into more simplicity and security. Always try to find solution of your problem and code examples for the same XCode and device firmware version as the one you are using.