I get
An SSL error has occurred and a secure connection to the server cannot be made.
on iOS 9 if I try to download a file fr
Until Amazon gets their head out of their *ss on this one, as @Zsolt suggested insert the following keys and value in your plist file.
BUT be sure to set the NSExceptionDomain to amazonaws.com instead of s3.amazonaws.com, depending on how your assets are served and from which region amazon may serve them such as this s3-us-west-1.amazonaws.com
, so not explicitly setting the subdomain will allow assets to be properly served from any AWS region identifier.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>amazonaws.com</key>
<dict>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
Since S3 is not currently fully compliant, according to this post on the AWS blog, their official recommendation is to exclude S3 from App Transport Security by adding this set of keys to your Info.plist
:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>amazonaws.com</key>
<dict>
<key>NSThirdPartyExceptionMinimumTLSVersion</key>
<string>TLSv1.0</string>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
<key>amazonaws.com.cn</key>
<dict>
<key>NSThirdPartyExceptionMinimumTLSVersion</key>
<string>TLSv1.0</string>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
UPDATE 10/27/15: As Pol points out in the comments, even though this is an official answer from AWS, an Apple Engineer in the support forums says this is actually a bug:
It turns out that the fact that NSExceptionRequiresForwardSecrecy relaxes the SHA-2/256 requirement is a bug; the intended behaviour of NSExceptionRequiresForwardSecrecy is the behaviour documented in the App Transport Security Technote, namely that it should just enable specific cypher suites.
Our plan is to fix this bug at some point in the future. We expect to fix this in some compatible fashion, so folks who’ve mistakenly used NSExceptionRequiresForwardSecrecy to disable the SHA-2/256 requirement won’t break. However, predicting the future is always a challenge. Which brings us to what you should do right now. [A previous version of this post gave less concrete advice. The following is an update that tightens things up.] After discussing this with ATS Engineering our recommendations are:
If you're using a specific hosting service, you should consult your hosting service to get the latest advice.
In situations like this, where the server is fully compatible with ATS except for the SHA-2/256 certificate signing requirement, we recommend that you accurately document that state of affairs by using NSExceptionAllowsInsecureHTTPLoads.
You should attempt to make your server fully compatible with ATS as soon as possible.
When that happens, you should update your app with the more secure ATS settings.
I should stress that NSExceptionAllowsInsecureHTTPLoads isn't actually insecure. It's just as secure as your app currently is when it's running on iOS 8. Rather, it means that your app doesn't benefit from the extra security provided by ATS. Share and Enjoy
Emphasis mine. Note that the current plan is to fix the bug in a way that will not break the behavior for people who have used NSExceptionRequiresForwardSecrecy
to solve this issue, so the above is still a viable answer.
Edit 2016-01-03: The renewed certificate for s3.amazonaws.com uses the SHA256 algorithm and complies with ATS requirements.
Original answer: s3.amazonaws.com uses a SHA1 cerificate that does not meet ATS requirements, resulting in a hard failure. Per the App Transport Security Technote, ATS in iOS9 has the following requirements:
The server must support at least Transport Layer Security (TLS) protocol version 1.2.
Connection ciphers are limited to those that provide forward secrecy, namely,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
Certificates must be signed using a SHA256 or better signature hash algorithm, with either a 2048 bit or greater RSA key or a 256 bit or greater Elliptic-Curve (ECC) key.
Invalid certificates result in a hard failure and no connection.
SSL Labs' SSL server test (https://www.ssllabs.com/ssltest/analyze.html?d=s3.amazonaws.com) includes a handshake simulation for ATS in iOS 9 that indicates a failure for s3.amazonaws.com.
Just posting to point out that the issue with amazon's certificates are they use SHA-1 and the app transport security requires SHA-2/256.
The fact that NSExceptionRequiresForwardSecrecy works is a bug documented here at apple dev forums. According to the documentation and an Apple engineer in the linked thread a "better" solution would be
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>s3.amazonaws.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
I use the term "better" very loosely and only mean a solution that does not exercise a bug that Apple will eventually fix. Now this is a fix for the certificate issue only :)
You need two things to have iOS 9 app successfully reaching SSL endpoint (S3 is just an example):
Forward Secrecy (https://www.wikiwand.com/en/Forward_secrecy) enabled on the server.
This feature is currently not supported by AWS S3. The workaround for that is that you can configure AWS CloudFront service (which supports FS) in front of your S3 bucket. Set up is fairly easy. If you're using CORS, please keep in mind that proper headers need to be passed through the CloudFront proxy.
SHA-256 protected SSL certificate on the server.
Once you'll have your files available via Cloudfront, when hitting URL (https://somethinghashed1234wasdfawer421.cloudfront.net) you'll notice that the SSL certificate over there uses SHA-1. How bad... The solution for that is to protect this with your private, SHA-256 SSL cert. To do that you need to specify CNAME for Cloudfront endpoint in your domain. This will allow you to secure the bucket with your own SSL certificate. Simply configure your DNS to have entry pointing cloudfront-bucket.mydomain.com to that ugly somethinghashed1234wasdfawer421.cloudfront.net. Upload your SSL cert to amazon and set SSL protection in Cloudfront distribution settings. Voila!
All things mentioned are easily clickable from AWS console (apart from uploading SSL cert, which needs to be done via AWS CLI).