18 Feb 2015

PHP 5.6 and UPS’s Web Services

This has been an extremely puzzling bug I’ve been trying to figure out while working on Package Stalker recently. Since updating my webserver to PHP 5.6, connections to UPS’s web services host, wwwcie.ups.com, have been failing intermittently, with no distinguishable pattern between which connections succeed and which fail.

After lots of debugging, I found this note in PHP’s documentation:

The default ciphers used by PHP have been updated to a more secure list based on the Mozilla cipher recommendations, with two additional exclusions: anonymous Diffie-Hellman ciphers, and RC4.

With PHP’s error messages being unhelpful as usual, I used OpenSSL’s s_client command to debug the connection:

openssl s_client -cipher 'HIGH:!RC4' -connect wwwcie.ups.com:443

It seemed to connect successfully… most of the time. About 1 in 3 attempts, I’d get this message:

3073504956:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:769:

This matched exactly the error being produced in PHP.

Upon examining the output further, it seems that sometimes when you connect to UPS’s web service, you get a nice, up-to-date box that sends you a TLSv1.2 handshake and supports the DHE-RSA-AES256-GCM-SHA384 cipher suite. But other times, you end up with a horribly outdated box that only supports TLSv1.0 with RC4-SHA as the only supported cipher suite!

What’s going on here? In all likelihood, UPS is using a simple load-balancer such as haproxy to handle inbound connections, and handling TLS directly at the server level; it seems that one of the tracking servers is misconfigured to only use RC4 cipher suites. I’ve contacted UPS’s Developer Resources department to alert them of the issue.

In the mean time, to work around this in PHP 5.6, use the following stream context options if you’re setting up the connection yourself:

$ctx = stream_context_create([
	'ssl' => [
		'crypto_method' => STREAM_CRYPTO_METHOD_ANY_CLIENT,
		'capture_session_meta' => true,
		'ciphers' => 'DEFAULT:RC4-SHA'
	]
]);

$connection = stream_socket_client("ssl://wwwcie.ups.com:443", $errno, $errstr, 10, STREAM_CLIENT_CONNECT, $ctx);

If you’re using cURL, this is even easier – just set CURLOPT_SSL_CIPHER_LIST:

curl_setopt($handle, CURLOPT_SSL_CIPHER_LIST, 'DEFAULT:RC4-SHA');

I’ll update this post with anything I hear from UPS.

Posted in Uncategorized

No Responses to “PHP 5.6 and UPS’s Web Services” (post new)

 

Leave a Reply