42

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 from amazon s3: https://s3.amazonaws.com/xyz/qer/IMG_0001.JPG

From what I understand Amazon s3 supports TLS 1.2 see: https://forums.aws.amazon.com/thread.jspa?threadID=192512

S3 and Kinesis support TLS 1.2 at this time.enter image description here

"S3 and Kinesis support TLS 1.2 at this time." Aug 23, 2015 9:19 PM

Not sure then why do I get this SSL error. The account should be configured to take advantage of TLS 1.2? I would've guessed that this should be 'on' by default.

I don't want to put this domain on the info plist.

EDIT: I ended up using

<key>NSAppTransportSecurity</key> 
<dict> 
  <key>NSExceptionDomains</key> 
  <dict> 
    <key>s3.amazonaws.com</key> 
    <dict> 
      <key>NSExceptionRequiresForwardSecrecy</key> 
        <false/> 
      <key>NSIncludesSubdomains</key> 
        <true/> 
    </dict> 
  </dict> 
</dict>
Manos Nikolaidis
  • 18,967
  • 11
  • 60
  • 72
Zsolt
  • 3,381
  • 3
  • 28
  • 44
  • 2
    adding those keys and dict values to my plist made this error message go away... – Bill Noto Sep 15 '15 at 00:47
  • 1
    Right. This has been outlined in http://mobile.awsblog.com/post/Tx2QM69ZE6BGTYX/Preparing-Your-Apps-for-iOS-9 and is a good way to sweep things under the carpet. I really hope Amazon sorts this out without needing developers write exceptions for them – Anand Bhat Sep 18 '15 at 16:44
  • 1
    An long-time and well-respected Apple engineer said at https://forums.developer.apple.com/thread/13472 that `NSExceptionRequiresForwardSecrecy` should NOT be used to work around this issue: "It turns out that the fact that NSExceptionRequiresForwardSecrecy relaxes the SHA-2/256 requirement is a bug". Use `NSExceptionAllowsInsecureHTTPLoads` instead. – Pol Oct 25 '15 at 16:43

5 Answers5

39

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:

  1. The server must support at least Transport Layer Security (TLS) protocol version 1.2.

  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

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

Dev SSL Labs

Anand Bhat
  • 4,998
  • 25
  • 30
12

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

Community
  • 1
  • 1
mieciu
  • 408
  • 3
  • 7
  • What's the source that says that forward secrecy is not supported by S3? I couldn't find anything obvious. – Pol Oct 25 '15 at 16:48
  • Can't think of any source, I've verified that with one of my SSL debugging tools (nmap, openssl client or some on-line, browser app). – mieciu Oct 26 '15 at 19:08
  • Is this an issue with AWS S3 instances in general, or specific servers running on these servers? (I'm running my own custom server). – Chris Prince May 25 '17 at 05:02
11

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.

markquezada
  • 8,138
  • 6
  • 42
  • 50
  • 1
    This worked for me, I'm using latest AWS SDK v2.2.6, you might need to update your SDK. – Zee Sep 29 '15 at 14:36
  • 1
    An long-time and well-respected Apple engineer said at https://forums.developer.apple.com/thread/13472 that `NSExceptionRequiresForwardSecrecy` should NOT be used to work around this issue: "It turns out that the fact that NSExceptionRequiresForwardSecrecy relaxes the SHA-2/256 requirement is a bug". Use `NSExceptionAllowsInsecureHTTPLoads` instead. – Pol Oct 25 '15 at 16:42
6

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

Pol
  • 3,538
  • 1
  • 31
  • 51
tmeisenh
  • 1,416
  • 1
  • 13
  • 11
  • When I first tried this solution and it did not work for me and then I noticed that the S3 URL was slightly different. Instead of s3.amazonaws.com, try to use amazonaws.com (without the s3). This worked for me. – Vladan Sep 30 '15 at 21:49
  • @Vladan: changing the url as you describe did not work for me. – seeker12 Oct 02 '15 at 20:07
1

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>