SSL problems with S3/AWS using the Java API: "hostname in certificate didn't match"

Original: October 2012

Turns out that Amazon "upgraded" the SSL security on S3 in late September 2012. This broke access any S3 buckets that have periods in their name when using Amazon's AWS Java API.

This is inaccurate. S3's SSL wildcard matching has been the same as when S3 launched back in 2006. What's more likely is that the AWS Java SDK team enabled stricter validation of SSL certificates (good), but ended up breaking bucket names that have been running afoul of S3's SSL cert (bad).

The right answer is that you need to use path-style addressing instead of DNS-style addressing. That is the only secure way of working around the issue with the wildcard matching on the SSL certificate. Disabling the verification opens you up to Man-In-The-Middle attacks.

What I don't presently know is if the Java SDK provides this as a configurable option. If so, that's your answer. Otherwise, it sounds like the Java SDK team said "we'll add this feature, and then add integration tests to make sure it all works."

Update: October 2020

AWS has announced that path-style addressing is deprecated will be going away in the near-future. AWS’ advice is to use DNS-compatible bucket names, which means no periods (among a few other things). Certain newer features of S3 require DNS-compatible bucket names (e.g., accelerated transfer).

If you require a bucket name which contains periods (which will also be disallowed for new buckets in the near future), my best advice is to put a CloudFront distribution in front of it if you want to hit it over HTTPS.


Amazon released version 1.3.22 which resolves this issue. I've verified that our code now works. To quote from their release notes:

Buckets whose name contains periods can now be correctly addressed again over HTTPS.

There are a couple of solutions that I can see, aside from waiting till Amazon releases a new API.

  1. Obviously you could roll back to 1.3.20 version of the AWS Java SDK. Unfortunately I needed some of the features in 1.3.21.

  2. You can replace the org.apache.http.conn.ssl.StrictHostnameVerifier in the classpath. This is a hack however which will remove all SSL checking for Apache http connections I think. Here's the code that worked for me: http://pastebin.com/bvFELdJE

  3. I ended up downloading and building my own package from the AWS source jar. I applied the following approximate patch to the HttpClientFactory source.

    ===================================================================
    --- src/main/java/com/amazonaws/http/HttpClientFactory.java     (thirdparty/aws)      (revision 20105)
    +++ src/main/java/com/amazonaws/http/HttpClientFactory.java     (thirdparty/aws)    (working copy)
    @@ -93,7 +93,7 @@
    
                            SSLSocketFactory sf = new SSLSocketFactory(
                                    SSLContext.getDefault(),
    -                               SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
    +                               SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    
  4. The right fix is to change from domain-name bucket handling to path based handling.

Btw, the following seems like it might work but it does not. The AWS client specifically requests the STRICT verifier and does not use the default one:

SSLSocketFactory.getSystemSocketFactory().setHostnameVerifier(
    SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);