Why can ATS not be disabled in iOS Simulator?

Trying to make NSURLConnection to a server on a VirtualBox VM on my local machine. The server is a test env with a self-signed RSA 2048-bit cert.

Apache SSL is configured thusly:



SSLProtocol ALL -SSLv2 -SSLv3 SSLHonorCipherOrder On SSLCipherSuite ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS

SSLCompression off

SSLSessionCache shmcb:/var/cache/mod_ssl/scache(512000)

SSLSessionCacheTimeout 300

<VirtualHost *:443>

   ServerName mydomain.com

   DocumentRoot "/var/www/html/example/Web"

   SSLEngine On

   SSLOptions +StrictRequire

   SSLCertificateFile /etc/ssl/certs/server.crt

   SSLCertificateKeyFile /etc/ssl/private/server.key

</VirtualHost>


Wireshark shows that the client hello and server hello happen just fine.


But we see in the

/usr/bin/nscurl --ats-diagnostics https://example.com --verbose
shows fail on all counts, and indicates the rejection of the server's cert is because it is invalid (it's self-signed; I know it's invalid).


Supposedly you can add the "Allow Arbitrary Loads" to Info.plist to disable ATS in iOS 9, but I did this, and it does nothing. Client still rejects the self-signed cert.

Any ideas how I can make this work? I think maybe it's a problem specific to iOS simulator?


Not sure because shouldn't the nscurl test show at least one pass (the one where ATS is disabled)?

Accepted Reply

OK I finally got OS X Server 5 to work with TLS 1.2 and forward secrecy, making ATS perfectly happy 😀


1. Install Homebrew and brew install openssl, brew install PCRE

2. Download the latest source for Apache, apr, and apr-util

3. Extract Apache source into /usr/local/src/httpd-2.4.17

4. Extract apr and apr-util archives to /usr/local/src/httpd-2.4.17/srclib/apr and /usr/local/src/httpd-2.4.17/srclib/apr-util

5. Replace the character "+" with the word "apache2" in the files config.layout inside the apr and apr-util dirs

6. In Terminal, execute the following commands:

  • cd /usr/local/src/httpd-2.4.17
  • CFLAGS="-arch x86_64" ./configure --prefix=/usr/local/apache-2.4.17 --with-included-apr --with-included-apr-util -with-mpm=prefork --with-ssl=/usr/local/opt/openssl --enable-mods-shared=reallyall --enable-layout=Darwin
  • make
  • make install

7. Copy mod_hfs_apple.so, mod_authnz_ldap.so, and mod_ldap.so from /usr/libexec into /usr/local/apache-2.4.17/modules

8. Disable SIP: Restart into Recover mode (command-R), open Terminal, and type csrutil disable

9. Restart back into normal mode, open Terminal, and type the following commands:

  • sudo mv /usr/sbin/httpd /usr/sbin/httpd.old
  • sudo mv /usr/libexec/apache2 /usr/libexec/apache2.old
  • sudo ln -s /usr/local/apache-2.4.17/bin/httpd /usr/sbin/httpd
  • sudo ln -s /usr/local/apache-2.4.17/modules /usr/libexec/apache2

10. Re-enable SIP: restart into Recover mode, open Terminal, and type csrutil enable

11. Download the latest source for PHP and extract to /usr/local/src/php-5.6.16 (or whatever version; 7.0 just came out with scalar typing O.o)

12. Configure PHP with the following command (modify as needed, but this worked for my LAMP stack with OS X Server 5):

  • ln -s /usr/local/opt/openssl /usr/local/openssl
  • cd /usr/local/src/php-5.6.16
  • CFLAGS="-arch x86_64" ./configure --with-openssl=/usr/local/opt/openssl \

    --with-pcre-regex=/usr/local/opt/pcre \

    --with-curl=/usr/bin/curl \

    --enable-exif \

    --with-mysql=/usr/local/mysql \

    --with-mysql-sock=/tmp/mysql.sock \

    --with-pdo-mysql \

    --enable-opcache \

    --with-apxs2=/usr/local/apache-2.4.17/bin/apxs \

    --prefix=/usr/local/apache-2.4.17/php/ \

    --enable-sockets \

    --enable-zip \

    --with-pear=/usr/local/apache-2.4.17/lib/php \

    --enable-mbstring \
    --with-mysqli

  • make
  • make install

13. In a text editor, edit the file:

/Library/Server/Web/Config/Proxy/servermgr_serviceproxy_customsites.plist

Starting at line 65, perform these changes: (lines to delete, new lines)


<string>SSLCipherSuite &quot;ALL:!aNULL:!ADH:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM&quot;</string>

<string>SSLCipherSuite &quot;ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS&quot;</string>

<string>SSLHonorCipherOrder On</string>

<string>SSLProtocol -ALL +TLSv1</string>

<string>SSLProtocol -SSLv2 -SSLv3</string>


<string>SSLProxyProtocol -ALL +TLSv1</string>

<string>SSLProxyProtocol -SSLv2 -SSLv3</string>

14. Next, make a similar change in apache_serviceproxy_customsites.conf, starting at line 13:


SSLCipherSuite "ALL:!aNULL:!ADH:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM"

SSLHonorCipherOrder On

SSLCipherSuite "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS"


SSLProtocol -ALL +TLSv1

SSLProtocol ALL -SSLv2 -SSLv3


SSLProxyProtocol -ALL +TLSv1

SSLProxyProtocol ALL -SSLv2 -SSLv3


15. Next, make the exact same changes as in step 14., in apache_serviceproxy.conf, starting at line 198.


16. Next, make the exact same changes to any custom sites that you have already configured with SSL in OS X Server. Their files will be found at a path like this:

/Library/Server/Web/Config/apache2/sites/0000_127.0.0.1_34543_[[your custom site's url]].conf


17. Start OS X server and run the following command to verify that you have succeeded:

/usr/bin/nscurl --ats-diagnostics https :// [[your custom site's https url]]

Note: the URL will obviously need to be formatted properly. I put an extra space in there before the colon because otherwise this post gets sent to moderation.


In my case ALL of the tests came back with a "PASS."

Replies

ATS provides extra security above and beyond the normal HTTPS server trust evaluation done by earlier systems. Setting

NSAllowsArbitraryLoads
disables ATS’s extra security but the standard HTTPS server trust evaluation is still in place. You can override that using the techniques described in Technote 2232 HTTPS Server Trust Evaluation.

However, a better approach is not not override HTTPS server trust evaluation but rather set up your own certificate authority (CA) and have that issue a certificate to your server. If you install the CA’s root certificate on your device (or simulator), you’ll be able to connect to the server ‘out of the box’, that is, with both the default ATS settings and default HTTPS server trust evaluation.

Setting up your own CA is easy to do on the Mac. See Technote 2326 Creating Certificates for TLS Testing.

The main advantage of this approach is that there’s no debug code that you might accidentally leave enabled in your production app. There’s been a number of high-profile developers who’ve done this in the past, resulting in embarrassing security vulnerabilities. Don’t be that guy!

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Roger that. I intend to use a Run Script to programatically set these trust-related settings at built-time based on whether the "Debug" configuration is selected, or unset them if the "Release" configuration is selected. Apple might consider building for OS X Server a streamlined, push-button method for creating your own certificate authority for testing LAMP stack stuff.


Edit: how do you install a root certificate on the simulator? It does not seem to have a "Profiles" section in preferences.

OK, to install a root certificate in the simulator you just drag and drop the certificate onto the device. Then I also added this to the info-plist:


<key>NSAppTransportSecurity</key>

<dict>

<key>NSExceptionDomains</key>

<dict>

<key>beta.mydomain.com</key>

<dict>

<key>NSExceptionAllowsInsecureHTTPLoads</key>

<true/>

</dict>

</dict>

</dict>


And to run script:


if [ "$CONFIGURATION" == "Debug" ] ; then

/usr/libexec/PlistBuddy PDXEnterpriseSolutions/PDXEnterpriseSolutions-Info.plist -c "Set NSAppTransportSecurity:NSExceptionDomains:beta.hellojory.com:NSExceptionAllowsInsecureHTTPLoads YES"

fi

if [ "$CONFIGURATION" == “Release" ] ; then

/usr/libexec/PlistBuddy PDXEnterpriseSolutions/PDXEnterpriseSolutions-Info.plist -c "Set NSAppTransportSecurity:NSExceptionDomains:beta.hellojory.com:NSExceptionAllowsInsecureHTTPLoads NO"

fi

Problem with this is that you have to clean before building or else the run script seems to update the plist after it's already on the device/simulator.

Apple might consider building for OS X Server a streamlined, push-button method for creating your own certificate authority for testing LAMP stack stuff.

If you want this suggestion to be seen by the folks who work on OS X Server, you should put it in a formal enhancement request. Please post your bug number, just for the record.

OK, to install a root certificate in the simulator you just drag and drop the certificate onto the device.

Yep.

Then I also added this to the info-plist:

If your server uses a certificate issued by a trusted certificate authority, why do you need to modify the app’s ATS settings?

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Eskimo wrote:

If your server uses a certificate issued by a trusted certificate authority, why do you need to modify the app’s ATS settings?

Because OS X 10.11.1's Apache does not support anything past TLS 1.0, because OS X 10.11.1 only includes the ancient OpenSSL version 0.9.8zg.


OS X's built-in Apache is used in OS X Server 5.0.15, therefore it also does not support TLS 1.2, or even TLS 1.1.


I have submitted a Security issue for this. The Bug Report number is 23779687.


I find this shocking. What would Tim Cook say? I find it ridiculously shameful, frankly, that Apple's own server software is not compliant with TLS 1.2 even though the Technote you referred me to acts like all I need is a trusted certificate authority and I should be able to connect to sites served from my Mac and ATS will be happy.

PS—How do you make quoted text? I don't see any icon for it.

If your server uses a certificate issued by a trusted certificate authority, why do you need to modify the app’s ATS settings?

Because OS X 10.11.1's Apache does not support anything past TLS 1.0, because OS X 10.11.1 only includes the ancient OpenSSL version 0.9.8zg.


Fair enough. In that case, however, you’ll only need

NSExceptionMinimumTLSVersion
rather than
NSExceptionAllowsInsecureHTTPLoads
.

PS—How do you make quoted text? I don't see any icon for it.

I write in Markdown and then have a hotkey to paste in the HTML. I can’t see a way to quote text in the normal editor.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

EDIT:


OS X Server has a different bug which caused it to comment out my TLS 1.2 ciphers and then an even further bug which caused it to keep swapping my working certificates out with the "fallback" ones. OS X Server cannot deal with multi-line syntax as in my SSLCipherSuite argument below (it does not see that it's all one line, and comments those lines out, even though from Apache's perspective, it's perfectly valid). I will follow up with additional necessary steps when I figure out what they are, precisely—unless Apple happens to release an update in the mean time. Wouldn't that be nice?


BTW I got TLS 1.2 to work on OS X Server. It was a very convoluted process.

Here is what I had to do:

1. Disable System Integrity Protection (temporarily)

2. Download the latest source for Apache, apr, and apr-util

3. Brew Install PCRE and OpenSSL 1.0.2e

4. Copy apr and apr-util into srcdir of apache

5. Build Apache like this:

CFLAGS="-arch x86_64" ./configure --prefix=/usr/local/apache-2.4.17 --with-included-apr --with-included-apr-util -with-mpm=prefork --with-ssl=/usr/local/opt/openssl --enable-mods-shared=reallyall

6. Copy mod_hfs_apple.so, libphp5.so, mod_authnz_ldap.so, and mod_ldap.so from /usr/libexec into /usr/local/apache-2.4.17/modules

7. sudo mv /usr/sbin/httpd /usr/sbin/httpd.old

8. sudo mv /usr/libexec/apache2 /usr/libexec/apache2.old

9. sudo ln -s /usr/local/apache-2.4.17/bin/httpd /usr/sbin/httpd

10. sudo ln -s /usr/local/apache-2.4.17/modules /usr/libexec/apache2

11. Re-enable SIP

12. Set my custom site's ciphers in its /Library/Server/Web/Config/apache2/sites/0000_127.0.0.1_34543_my.frickity.url.com.conf directory to:

SSLCipherSuite \

"ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-\

AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-\

SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:\

ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:\

ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:\

ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-\

AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-\

SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:\

AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!\

DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!\

KRB5-DES-CBC3-SHA"

SSLHonorCipherOrder On

BOOM.

BTW: I hereby grant Apple permission to use this basic method to fix the Security issue I reported.

OK I finally got OS X Server 5 to work with TLS 1.2 and forward secrecy, making ATS perfectly happy 😀


1. Install Homebrew and brew install openssl, brew install PCRE

2. Download the latest source for Apache, apr, and apr-util

3. Extract Apache source into /usr/local/src/httpd-2.4.17

4. Extract apr and apr-util archives to /usr/local/src/httpd-2.4.17/srclib/apr and /usr/local/src/httpd-2.4.17/srclib/apr-util

5. Replace the character "+" with the word "apache2" in the files config.layout inside the apr and apr-util dirs

6. In Terminal, execute the following commands:

  • cd /usr/local/src/httpd-2.4.17
  • CFLAGS="-arch x86_64" ./configure --prefix=/usr/local/apache-2.4.17 --with-included-apr --with-included-apr-util -with-mpm=prefork --with-ssl=/usr/local/opt/openssl --enable-mods-shared=reallyall --enable-layout=Darwin
  • make
  • make install

7. Copy mod_hfs_apple.so, mod_authnz_ldap.so, and mod_ldap.so from /usr/libexec into /usr/local/apache-2.4.17/modules

8. Disable SIP: Restart into Recover mode (command-R), open Terminal, and type csrutil disable

9. Restart back into normal mode, open Terminal, and type the following commands:

  • sudo mv /usr/sbin/httpd /usr/sbin/httpd.old
  • sudo mv /usr/libexec/apache2 /usr/libexec/apache2.old
  • sudo ln -s /usr/local/apache-2.4.17/bin/httpd /usr/sbin/httpd
  • sudo ln -s /usr/local/apache-2.4.17/modules /usr/libexec/apache2

10. Re-enable SIP: restart into Recover mode, open Terminal, and type csrutil enable

11. Download the latest source for PHP and extract to /usr/local/src/php-5.6.16 (or whatever version; 7.0 just came out with scalar typing O.o)

12. Configure PHP with the following command (modify as needed, but this worked for my LAMP stack with OS X Server 5):

  • ln -s /usr/local/opt/openssl /usr/local/openssl
  • cd /usr/local/src/php-5.6.16
  • CFLAGS="-arch x86_64" ./configure --with-openssl=/usr/local/opt/openssl \

    --with-pcre-regex=/usr/local/opt/pcre \

    --with-curl=/usr/bin/curl \

    --enable-exif \

    --with-mysql=/usr/local/mysql \

    --with-mysql-sock=/tmp/mysql.sock \

    --with-pdo-mysql \

    --enable-opcache \

    --with-apxs2=/usr/local/apache-2.4.17/bin/apxs \

    --prefix=/usr/local/apache-2.4.17/php/ \

    --enable-sockets \

    --enable-zip \

    --with-pear=/usr/local/apache-2.4.17/lib/php \

    --enable-mbstring \
    --with-mysqli

  • make
  • make install

13. In a text editor, edit the file:

/Library/Server/Web/Config/Proxy/servermgr_serviceproxy_customsites.plist

Starting at line 65, perform these changes: (lines to delete, new lines)


<string>SSLCipherSuite &quot;ALL:!aNULL:!ADH:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM&quot;</string>

<string>SSLCipherSuite &quot;ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS&quot;</string>

<string>SSLHonorCipherOrder On</string>

<string>SSLProtocol -ALL +TLSv1</string>

<string>SSLProtocol -SSLv2 -SSLv3</string>


<string>SSLProxyProtocol -ALL +TLSv1</string>

<string>SSLProxyProtocol -SSLv2 -SSLv3</string>

14. Next, make a similar change in apache_serviceproxy_customsites.conf, starting at line 13:


SSLCipherSuite "ALL:!aNULL:!ADH:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM"

SSLHonorCipherOrder On

SSLCipherSuite "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS"


SSLProtocol -ALL +TLSv1

SSLProtocol ALL -SSLv2 -SSLv3


SSLProxyProtocol -ALL +TLSv1

SSLProxyProtocol ALL -SSLv2 -SSLv3


15. Next, make the exact same changes as in step 14., in apache_serviceproxy.conf, starting at line 198.


16. Next, make the exact same changes to any custom sites that you have already configured with SSL in OS X Server. Their files will be found at a path like this:

/Library/Server/Web/Config/apache2/sites/0000_127.0.0.1_34543_[[your custom site's url]].conf


17. Start OS X server and run the following command to verify that you have succeeded:

/usr/bin/nscurl --ats-diagnostics https :// [[your custom site's https url]]

Note: the URL will obviously need to be formatted properly. I put an extra space in there before the colon because otherwise this post gets sent to moderation.


In my case ALL of the tests came back with a "PASS."