While working on a client's website and servers for CF Webtools we ran into a perplexing problem with CFHTTP and SSL. We were working on setting up payment processing using ColdFusion 8.0.1 (yes, I know it's ancient but the client is planning to upgrade to CF10 soonish) and it needed to communicate with a clients .NET server via secure CFHTTP (meaning over SSL). The problem was that SSL communications was failing. The error (below) was I/O Exception: peer not authenticated.
For several hours we tried everything from importing the SSL into the keystore to creating a separate keystore and including it in the jvm.config. We checked name resolution and tried different Java versions. The issue persisted even after upgrading the JVM to 1.6.0_45. We even tested from ColdFusion 9.0.1 and ColdFusion 10u9 running on Java 1.6.0_29 and nothing was working. Usually we can resolve SSL issues in short order. This issue, however, was beginning to seem like something on the server was preventing SSL communications - except for one nagging fact. When using a web browser on the server we could access the payment gateway web service url via SSL with no problem. So SSL was working and all tests indicated that the SSL certificate was installed correctly. What could be the problem?
After discussing the issue a bit more with our customer and explaining our dilemma they decided to grant me access to their payment gateway .NET server. As soon as I logged on I found a couple clues. The server is running Windows Server 2012 and IIS 8. Both are new to me, but that never stopped me before. I set out to learn something new. While getting used to the new UI I found a setting for SSL in IIS that I've never seen before; Use Server Name Indication (SNI). What the heck is SNI? In addition, instead of the IIS site having the SSL Cert specifically assigned to it, the setting was set to use the Centralized Certificate Store. Again what is this?
A few searches later I learned that Server Name Indication (SNI) is the HTTPS equivalent of Name Virtual Hosts for HTTP. Wow! Remember back in the day when there was a one to one relationship between IP addresses and websites? Web servers couldn't serve more than one web site from a single IP. But the addition of the "host header" setting to the HTTP protocol allowed the web server to "figure out" what site to use to serve up content - allowing for fewer IP addresses to be needed for the grand world wide web experiment. SNI does the same thing for SSL certificates. Up until now you needed a one to one relationship between IP addresses and certificates - one IP to one standard certificate (we'll leave wild cards for another post). But now, SSL will no longer need a dedicated IP address per certificate. So multiple certificates combined with multiple host headers can serve secure content from a single IP address. If you want to dig deeper (and I'm still digging myself) here's the wiki page for Server Name Indication.
Granted the SNI protocol has been a part of TLS for a while, but it has only become practical recently. Indeed, it's only in IIS 8 that Microsoft made it available. Leveraging SNI, MS also created Centralized Certificate Store - a neat new feature that allows you to create a central location for Certificates that all of the servers in a cluster can access. Thus, implementing or updating a certificate for a groups of servers is (theoretically) a simple process of updating a single Centralized Certificate Store. I won't go into the details of SNI and CCS - mainly because I am still learning them myself - but let's talk about how this affects ColdFusion and CFHTTP over SSL.
One of the gotchas is that the client/browser needs to be able to use SNI. It's an extension of the TLS protocol so the client needs to be able to use TLS. Most but not all clients/browsers are compatible. While Java can use TLS (also sometimes referenced as SSL 3.0 - see this post by Mark Kruger, aka the ColdFusion Muse for a good explanation of TLS), it's only since Java 1.7 that Java can use TLS with the SNI extension. This gotcha prevents ColdFusion, while running on Java 1.6 and older, from working with SSL via CFHTTP when the server being targeted is configured for SNI. In fact ColdFusion 8 will never work with SNI as it can only run on Java 1.6 and older. ColdFusion 9 and ColdFusion 10 at least have a chance because both are capable of running on Java 1.7.
To follow through and give complete info for this blog post I upgraded a couple of my dev work stations for further testing. Flash forward after doing updates and testing and still no joy. After updating ColdFusion 10 to update 11 and configuring it to run on Java 1.7.0_25 I gave the code another round of testing. I reenabled SNI on the target IIS 8 installation. As I feared ColdFusion 10 could not communicate with the remote server over SSL. Disabling SNI allowed CFHTTP to work again. There is probably no point in testing a CF9 server though we do have a couple CF9 servers running on Java 1.7 at CF Webtools.
In my view this could be an increasingly critical issue as more servers throughout the Internet are upgraded to Windows 2012 and IIS 8. ColdFusion is routinely used to make remote calls to other servers over SSL and it obviously needs to be updated to use this new standard. I suspect, given its convenience and implications, that many Windows server administrators will want to leverage this feature. As for our customer he is fine with not using SNI for the time being. His server is dedicated to this one task with only one domain hosted. Meanwhile I entered a bug in Adobe's bug database at this URL. Please don't hesitate to vote it up.
Is there a "Fall Back" for SNI if a browser does not support it? Unfortunatley not. But there is a work around for IIS 8 that requires you to setup a second site that does not have SNI enabled. In other words you have one site that handles SNI through the central repository and another site that works "the old way" and is bound to an individual IP address. Of course this appears to negate the whole point of SNI.