LWN.net Logo

Holes discovered in SSL certificate validation

By Jake Edge
October 31, 2012

A stinging indictment of the state of SSL client applications was recently published as part of the Proceedings from the ACM Computer and Communications Security (CCS) conference. The six authors of the paper (three each from Stanford and The University of Texas) describe testing that certainly should have been done as part of the application development process, but clearly wasn't. The problem stems partly from the libraries that provide SSL certificate verification, because developers are not using them properly. By and large the low-level library cryptographic protocol implementations are fine, the authors found, but the APIs are designed so poorly that developers commonly misuse them.

The paper [PDF] is entitled "The Most Dangerous Code in the World: Validating SSL Certificates in Non-Browser Software" and lives up to that label. It is truly an eye-opening read. The researchers simulated man-in-the-middle attacks using a combination of self-signed and invalid SSL certificates along with a valid certificate for the amusing AllYourSSLAreBelongTo.us domain to observe the effects on various applications. The observations led to the overall conclusion: "SSL certificate validation is completely broken in many critical software applications and libraries".

The researchers used Windows and Ubuntu laptops, a Nexus One smartphone, and an iPad 2 as clients for their testing. A second Ubuntu system running custom Java and C proxies, as well as the Fiddler web debugging proxy, served as the man in the middle. As they noted, the kind of attack that can be launched from the proxies is precisely what SSL is meant to thwart—their testing did not go beyond what an active man in the middle could do:

This is exactly the attack that SSL is intended to protect against. It does not involve compromised or malicious certificate authorities, nor forged certificates, nor compromised private keys of legitimate servers. The only class of vulnerabilities we exploit are logic errors in client-side SSL certificate validation.

What they found was client applications that largely (or completely) accepted various kinds of invalid certificates and blindly sent private information (cookies, authentication information, credit card numbers) over an unsecured link. In many cases, the proxies could make the actual SSL connection to the remote server and funnel the data along—while surreptitiously storing the data away for (ab)use at a later time.

The paper gives plenty of examples of where the applications go wrong. Much of it can be blamed on bad library APIs, they said, in essentially all of the low-level SSL libraries (OpenSSL, GnuTLS, JSSE, CryptoAPI, etc.):

The root cause of most of these vulnerabilities is the terrible design of the APIs to the underlying SSL libraries. Instead of expressing high-level security properties of network tunnels such as confidentiality and authentication, these APIs expose low-level details of the SSL protocol to application developers. As a consequence, developers often use SSL APIs incorrectly, misinterpreting and misunderstanding their manifold parameters, options, side effects, and return values.

While that is certainly a problem, the application authors do bear some of the responsibility as well. It is not difficult to test an application against a few types of bad certificates. Because of the complexity of the APIs, developers should probably have been more wary that they might have made a mistake. Given that there is some kind of security requirement for the application (why use SSL otherwise?), it would seem prudent to verify proper functioning. Using a well-tested, industry-standard library is certainly an important piece of the puzzle, but there is more to it than just that.

There is also the problem of higher-level libraries perched atop OpenSSL, et al. The researchers found that libraries like Apache HttpClient, cURL, and the PHP and Python SSL libraries all had flaws in certificate validation. In fact, Python's urllib, urllib2, and httplib documentation warns that no certificate checking is done by the libraries, which evidently doesn't stop "high security" applications from still using them. One of the examples shows how this can all go awry:

Amazon's Flexible Payments Service PHP library attempts to enable hostname verification by setting cURL's CURLOPT_SSL_VERIFYHOST parameter to true. Unfortunately, the correct, default value of this parameter is 2; setting it to true silently changes it to 1 and disables certificate validation. PayPal Payments Standard PHP library introduced the same bug when updating a previous, broken implementation.

These kinds of errors would almost be comical, if they weren't so serious. While it may sound difficult for attackers to position themselves "in the middle", the prevalence of wireless networking these days makes it easier. Taking over an access point (or just running a hostile one as "Free Airport WiFi", say) puts an attacker squarely in the middle. Users that are running the vulnerable applications over a link to a bad access point are susceptible to many kinds of attacks. Compromise of home routers is another possibility. Obviously, malware running upstream in the wired internet is equally dangerous (if harder to pull off).

The researchers conclude the article with recommendations for both application and SSL library developers. For the most part, they are pretty common-sense suggestions (do test your application, don't have multiple inconsistent error reporting mechanisms, etc.) that could certainly apply more widely than just SSL applications and libraries. Obviously, they could not test each and every non-browser SSL-using client (or even all of the SSL client libraries) out there, but the list of vulnerable components from the abstract is rather astonishing:

Vulnerable software includes Amazon's EC2 Java library and all cloud clients based on it; Amazon's and PayPal's merchant SDKs responsible for transmitting payment details from e-commerce sites to payment gateways; integrated shopping carts such as osCommerce, ZenCart, Ubercart, and PrestaShop; AdMob code used by mobile websites; Chase mobile banking and several other Android apps and libraries; Java Web-services middleware—including Apache Axis, Axis 2, Codehaus XFire, and Pusher library for Android—and all applications employing this middleware.

Perhaps the most distressing piece of this research is the appearance—at least—that developers are being pretty cavalier about checking the security baked into their supposedly "high security" applications. Beyond that, it is amazing that payment processors who are dealing with credit cards (and, importantly, credit card fraud) have seemingly not been very diligent about the code they distribute to their customers. All in all, this research shows that even "secure" applications and libraries often skimp on important verification testing—a seriously sad state of affairs.


(Log in to post comments)

Enterprise software purposefully circumventing certificates

Posted Nov 1, 2012 8:34 UTC (Thu) by pkolloch (subscriber, #21709) [Link]

Many developers seek to circumvent certificate verification on purpose: For convenience. While it might make sense for the testing environment, it certainly is a risk for production.

One example from the Java Play Framework 1.2.x:

https://github.com/playframework/play/blob/aef222a2e8859f...

Man-in-the-middle software

Posted Nov 1, 2012 10:44 UTC (Thu) by epa (subscriber, #39769) [Link]

So is there an easily deployable man-in-the-middle SSL sniffer that can be used for testing? Like a live CD you can boot on a PC with two Ethernet connections and forwards the traffic, giving you a report on SSL data it was able to intercept?

Man-in-the-middle software

Posted Nov 1, 2012 10:44 UTC (Thu) by epa (subscriber, #39769) [Link]

...or better, some purely software SSL sniffer that you can route a virtual network interface through...

Man-in-the-middle software

Posted Nov 1, 2012 14:07 UTC (Thu) by TRS-80 (subscriber, #1804) [Link]

Man-in-the-middle software

Posted Dec 18, 2012 21:58 UTC (Tue) by speculatrix (guest, #62766) [Link]

http://portswigger.net/burp/

fantastic powerful tool for intecepting https traffic, modifying requests and responses, as well as logging.

Holes discovered in SSL certificate validation

Posted Nov 1, 2012 12:42 UTC (Thu) by zmower (subscriber, #3005) [Link]

Amazon's Flexible Payments Service PHP library attempts to enable hostname verification by setting cURL's CURLOPT_SSL_VERIFYHOST parameter to true. Unfortunately, the correct, default value of this parameter is 2; setting it to true silently changes it to 1 and disables certificate validation. PayPal Payments Standard PHP library introduced the same bug when updating a previous, broken implementation.
As an Ada programmer, I laughed hard at this. Static typing FTW!

Holes discovered in SSL certificate validation

Posted Nov 1, 2012 14:11 UTC (Thu) by sorpigal (subscriber, #36106) [Link]

I think you only have to be a competent programmer to laugh at PHP.

Holes discovered in SSL certificate validation

Posted Nov 1, 2012 15:00 UTC (Thu) by intgr (subscriber, #39733) [Link]

> Static typing FTW!

This vulnerability doesn't come from the lack of static typing, it comes from implicit type conversions (sometimes called "weak typing"). There are statically typed languages that allow implicit conversions from boolean to integer, such as C++, which could very well have the same vulnerability.

People frequently try to discredit dynamic typing with claims like "PHP uses dynamic typing. PHP makes it hard to write secure code. Therefore dynamic typing is insecure."

But the most problematic behaviors in PHP -- implicit conversion from strings to numbers, arrays to strings etc -- are not present in other dynamic languages like Python, Ruby and cause an exception to be thrown. And the conversion semantics are far less problematic even in JavaScript.

Holes discovered in SSL certificate validation

Posted Nov 1, 2012 17:15 UTC (Thu) by zmower (subscriber, #3005) [Link]

As an Ada programmer my static typing is implictly strong. ;) Don't get me started on C++...

Dynamic languages are OK if you want to get somewhere fast. I'll gladly use python to read the GPIO pins on my rpi. But I'd refuse to get on a plane where the control systems relied on it! (Not that all Ada software is well designed, written and tested but I can dream.)

Holes discovered in SSL certificate validation

Posted Nov 1, 2012 21:18 UTC (Thu) by zlynx (subscriber, #2285) [Link]

c++ introduced strongly typed enums. These are great. In the cURL SSL example it could be implemented with an enum named something like SSL_HOST_VERIFY_ON = 2. That value could then never be implicitly set by an integer, a boolean or anything except an enum of the right type.

Unfortunately we cannot go back in time to add features to old versions of C.

Holes discovered in SSL certificate validation

Posted Nov 2, 2012 7:21 UTC (Fri) by cmccabe (subscriber, #60281) [Link]

I'm glad that C++ finally introduced a version of enums that doesn't decay to ints. I probably will use that in the future if I'm writing C++0x code.

Still, I feel that it is unfair for you to criticize C for containing the bug referenced by the poster. C doesn't have a bool type, so there is no way that anyone could pass 'true' in a place where an enum was expected.

In my experience, C++'s addition of bool was not a good idea. The fact that any type of pointer implicitly converts to bool is the source of much hilarity when novices try to write C++ code. That problem does not exist in C because the numeric types there never implicitly convert to pointers.

Holes discovered in SSL certificate validation

Posted Nov 2, 2012 18:07 UTC (Fri) by zlynx (subscriber, #2285) [Link]

No, C does not have a boolean type. That doesn't change much though because pointers do get treated as boolean values.

It is very common to write if(pointer) { use(pointer); } in C code. That is a pointer being used as a boolean.

I think that you must have gotten confused about the pointer conversions somewhere. There aren't any cases in any version of C or C++ where a numeric type converts into a pointer silently.

Holes discovered in SSL certificate validation

Posted Nov 2, 2012 22:00 UTC (Fri) by nix (subscriber, #2304) [Link]

There aren't any cases in any version of C or C++ where a numeric type converts into a pointer silently.
Um, 0 in pointer context is the null pointer constant. (Sure, it doesn't apply to any other values of integral type, but still.)

Holes discovered in SSL certificate validation

Posted Nov 3, 2012 1:14 UTC (Sat) by nybble41 (subscriber, #55106) [Link]

>> There aren't any cases in any version of C or C++ where a numeric type converts into a pointer silently.
> Um, 0 in pointer context is the null pointer constant.

It's not just the value; in C99, at least, only an _integer constant expression_ with the value zero, or the same cast to (void*), can be implicitly converted to a null pointer. Any other expression with numeric type will not be implicitly treated as a null pointer, even if the value happens to be zero. GCC treats this as an integer-to-pointer conversion without a cast and generates a warning by default.

Granted, "false" from <stdbool.h> is a macro defined as the integer constant 0, so it can be converted to a null pointer. However, the null pointer is treated as false in a boolean context, so that isn't so very surprising.

Holes discovered in SSL certificate validation

Posted Nov 11, 2012 18:41 UTC (Sun) by cmccabe (subscriber, #60281) [Link]

Here is an example.

> #include <stdio.h>
> void dostuff(bool foo) {
> printf("foo = %d\n", foo);
> }
> int main(int argc, char **argv) {
> dostuff(argv);
> }

Compiles with no errors on -Wall, produces "foo = 1"

Change the bool to int and you get:

example.c: In function ‘main’:
example.c:6:3: warning: passing argument 1 of ‘dostuff’ makes integer from pointer without a cast [enabled by default]
example.c:2:6: note: expected ‘int’ but argument is of type ‘char **’

Conclusion: the C method is safer than the C++ method.

Start combining this with things like function overloading and default parameters, and what little type safety you had tends to evaporate. Take it from a C++ programmer for many years.

Holes discovered in SSL certificate validation

Posted Nov 2, 2012 7:22 UTC (Fri) by cmccabe (subscriber, #60281) [Link]

I thought Ada programmers were all hunted to extinction in the Reagan administration. How did you survive?

Holes discovered in SSL certificate validation

Posted Nov 2, 2012 12:25 UTC (Fri) by pflugstad (subscriber, #224) [Link]

Having seen some of the Ada code that makes up a flight management system (not controls, but still responsible for important stuff like flight speed indicators and other displays), I can easily say that it was as bad as any other language. Ada may be strongly typed, but that doesn't make bad programmers any better. And bad programmers create bad code in ANY language.

Holes discovered in SSL certificate validation

Posted Nov 3, 2012 10:26 UTC (Sat) by brouhaha (subscriber, #1698) [Link]

Certainly it's possible to write bad code in any language, and that's what usually happens. (Consequence of Sturgeon's Law?) However, that doesn't mean that choosing a language with better semantics (such as strong typing) won't dramatically reduce the occurrence of certain kinds of bugs.

IMHO, C doesn't even qualify as a high-level language. C++ perhaps does, but being nearly a superset of C, has basically all of the problems of C, plus some new ones. Javascript... don't even get me started on that one.

I was an Ada enthusiast many years ago, but haven't kept up with it because there's so little paying Ada work available. If I could find the time, I'd like to learn Scala. However, the work I can find is almost entirely C, C++, and Java.

Holes discovered in SSL certificate validation

Posted Nov 3, 2012 21:36 UTC (Sat) by dvdeug (subscriber, #10998) [Link]

I get the feeling that some drivers drive around cars that don't have mirrors; I mean, a bad driver can crash any car, so why do you need these things that make it easier not to crash the car?

Holes discovered in SSL certificate validation

Posted Nov 4, 2012 0:48 UTC (Sun) by pflugstad (subscriber, #224) [Link]

Just to be clear, I like strong typing as much as the next guy. I think it's one of the primary ways to show how you expect various types of variables to be used, which is one of the primary ways you reduce bugs.

But I've seen BAD Ada code - in safety serious situations. I've also seen really bad C & C++ code, where *attempting* to make the code strongly typed actually made the code worse. For example:

if ( classInstance == MANIFEST_CONSTANT )

the classInstance had an int operator(), so the compiler implicitly called that, and everything was fine. But because lint complained about different types, we ended up with:

if ( classInstance == (ClassType)MANIFEST_CONSTANT )

This instantiated a new instance of ClassType on the stack and then invoked operator==. This happened in 100's of places. And it even worked - until it ran out of stack. This was actually fairly painful to track down.

So - a fool with a (bad) tool is the main lesson here, but the tool is attempting to enforce strong typing, and the programmer blindly followed it.

I've seen similar stupidities in Ada code, so it doesn't save you any.

My point (I think) is that bad programmers easily trump strongly typed languages. It *might* lesson the problem - marginally. But in my experience, you OFTEN get the kind of stupidity I describe above, especially when development processes BLINDLY mandate running lint on your code and fixing all the warnings.

So I don't look to strongly typed languages as any kind of panacea. You can type silly things like converting a boolean to a 1 even there. You want good code: hire good, experienced programmers, and make them test their code.

On topic: I've tried to program against SSL's APIs. I totally agree with the article - they are HORRIFIC and I was just trying to do something trivial, nothing difficult like certificate verification.

Holes discovered in SSL certificate validation

Posted Nov 4, 2012 17:20 UTC (Sun) by mathstuf (subscriber, #69389) [Link]

> But I've seen BAD Ada code - in safety serious situations. I've also seen really bad C & C++ code, where *attempting* to make the code strongly typed actually made the code worse. For example:

This is just an instance of fast-and-loose type casting (which is one of the major problems with languages like PHP and JS) in C++, so I don't think your example is saying anything spectacular about C or C++. Same sheep, different wool.

> So I don't look to strongly typed languages as any kind of panacea. You can type silly things like converting a boolean to a 1 even there.

They're not a panacea, but they certain do help. At least in Haskell, such things either involve "unsafe" in the function name or start putting the IO monad all through your code. Those are both things I stand out as "something fishy" to me. That casting in the example would be a red flag for me as well. Casting constants, especially if it's an enum (and you're not in some dark corner of the project dealing with marshalling between languages or the network) is a pretty bad code smell.

> You want good code: hire good, experienced programmers, and make them test their code.

Agreed.

Holes discovered in SSL certificate validation

Posted Nov 5, 2012 2:31 UTC (Mon) by wblew (subscriber, #39088) [Link]

Strongly static types languages refuse to perform implicit conversion.

To be blunt, C, and thus C++'s, implicit type conversion is at the root of plenty of exploitable security defects.

Holes discovered in SSL certificate validation

Posted Nov 1, 2012 18:59 UTC (Thu) by robert_s (subscriber, #42402) [Link]

"In fact, Python's urllib, urllib2, and httplib documentation warns that no certificate checking is done by the libraries"

It is of course possible to make them do so using an approach similar to http://web.archive.org/web/20110125104752/http://www.much... (original url disappeared)

Though of course its not just working by default is the major failure here.

checking is not as simple as it seams

Posted Nov 1, 2012 22:28 UTC (Thu) by noxxi (subscriber, #4994) [Link]

In theory, it is not the task of a plain TLS library to check the name in the certificate, because these checks are application specific:
There is RFC2818 for https (used for XMPP and FTP too), which allows something like www*.domain or even w*w.domain, and forbids checking of common name if a subjectAltName is specified. Then there is RFC4513 for ldaps (used also for POP3, IMAP and NNTP), which contrary to RFC2818 does not allow wildcards in common name, but will check common name even if there are subjectAltNames, and allows only wildcards like *.domain. RFC3207 for SMTP doesn't have any real specification at all on how the certificate should be checked.
Another problem is, that these TLS libraries often only care about the TLS connection itself, e.g. have no access to the hostname to do the checking.
Given this chaos it is no wonder, that the names are not checked correctly, if they are checked at all.

As a maintainer of IO::Socket::SSL it took me some time to accept, that a TLS library should at least provide ways to make hostname verification easy. In IO::Socket::SSL you now just need to set the verification scheme to something like 'http','ldap'... and maybe provide the hostname.
Sadly Perl was not mentioned in the paper at all, but from what I see major libraries like LWP, Net::LDAP or Mojo all implement correct name checking by using the functionality provided by IO::Socket::SSL.

A similar problem is checking against the trusted certificate agencies (CA).
Most libraries expect the CA store to be provided by the user. If none are given no checking will be done. Only few have at least some sensible defaults: pythons httplib2 comes with a minimal CA store with only few CAs, while Perls LWP uses Mozilla::CA to get the CAs mozilla trusts.

Another problem is the verification of certificate revocations.
OpenSSL provides hooks for local certificate revocation lists (CRL), so most libraries using OpenSSL (like the default libs from Perl, Python or Ruby) offer an option to give a CRL path, but don't have a default. And they don't care about keeping the CRLs current. And while OpenSSL has itself an OCSP implementation to check the revocation status online, it does not have a (documented) API for it, so no libraries on top of OpenSSL provide such functionality. Other Implementations like mono don't even offer simple CRL checking.

In summary: The APIs of TLS libraries are broken in lots of other ways.
German readers might have a look at a talk I gave last year about these issues: http://noxxi.de/pws/2011/https.pdf

checking is not as simple as it seams

Posted Nov 5, 2012 13:14 UTC (Mon) by mirabilos (subscriber, #84359) [Link]

Ah, so that's where the wildcard specs come from. I hadn't realised there were different RFCs for them, even. Refer http://lists.nongnu.org/archive/html/lynx-dev/2012-11/msg... to why I am interested… damn, now need to go back to that code and review it.

But I’ll definitely have a look at your linked PDF, thanks!

Holes discovered in SSL certificate validation

Posted Nov 2, 2012 14:22 UTC (Fri) by jezuch (subscriber, #52988) [Link]

> Given that there is some kind of security requirement for the application (why use SSL otherwise?)

I guess they had "encryption" on the requirements list, so they just slapped on some calls to some SSL library they googled and said "done!". And nobody cared about the requirement, really, it was just there to make the software look good in the eyes of managers and potential clients.

I ran into this problem

Posted Nov 8, 2012 14:50 UTC (Thu) by basdebakker (guest, #60977) [Link]

One day my browser told me that gmail was returning an invalid certificate. It was a certificate for the correct domain, but signed by an untrusted authority. This was an actual MITM attack.

I noticed that my gmail notifier (checkgmail) just kept working! Apparently it didn't check the certificate. I ditched the notifier, changed my gmail password and sent an e-mail to the author of the notifier. Never got a reply, though.

I ran into this problem

Posted Nov 8, 2012 15:35 UTC (Thu) by cortana (subscriber, #24596) [Link]

Any idea who perpetrated the attack? Public wifi, an employer, etc.?

Copyright © 2012, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds