Monday, October 26, 2015

Testing Kerberos with Web Services using Apache Directory

Apache CXF supports Kerberos for web services both via the Kerberos Token Profile of WS-Security, where the kerberos ticket is conveyed as a BinarySecurityToken in the security header of the client request, and over HTTP via the Negotiate authentication scheme. If you are developing kerberos-enabled web services using a framework like Apache CXF, a natural question to ask is how to set up a Kerberos KDC to test your web services prior to deployment. This is the first of two blog posts that shows two different ways to easily set up a KDC using open source projects for kerberos integration testing.

At ApacheCon EU 2014 in Budapest, I attended a great talk by Emmanuel L├ęcharny entitled "Testing LDAP Implementations". The talk covered how the Apache Directory project can be used to easily deploy Kerberos and LDAP servers in your test-code via annotations. This was music to my ears, as I had written a bunch of tests in Apache CXF for both LDAP and kerberos that were not run as part of the normal build, as they required a local KDC to run successfully. After this talk I got involved in the Apache Directory project, and converted the tests in Apache CXF to use Apache Directory instead, so they could be run as part of the normal build cycle. I also made some small improvements which I'll describe as part of this post.

I've created a project in github that shows how to use Apache Directory to set up a KDC, and how to use Apache CXF to authenticate to a web service using Kerberos, for both JAX-RS and JAX-WS:
  • cxf-kerberos: This project contains a number of tests that show how to use Kerberos with Apache CXF.
Both test-cases use an annotation to load a kerberos.ldif file, containing the information required to set up Kerberos principals in the KDC for testing:

 Another annotation sets up the Directory Service:

Finally, an annotation adds a KDC server:

The "KRB" protocol was added as part of DIRSERVER-2031 in the 2.0.0-M20 release. Previously, you could specify either "TCP" or "UDP" for the protocol attribute when testing Kerberos. However, this meant that they could not share the same port. The "KRB" protocol generates both TCP and UDP transports on the port provided, or otherwise on a random port. Previously, the random port generation was not working, as it always defaulted to 1024. Random port generation is an essential feature for testing as part of a build cycle, as hard-coded ports tend to cause problems on continuous integration platforms. Using a random port also means that the krb5.conf file used by the CXF clients must be read in, and the random port substituted into the file before writing it out again, as otherwise the clients would have no way of knowing the port the KDC was running on.

Friday, October 23, 2015

A certificate revocation security vulnerability in Java

A few days ago, Oracle released a Critical Patch Update containing fixes for various security vulnerabilities. In particular, the update contained fixes for 25 security vulnerabilities in Java itself. One of them, CVE-2015-4868, was discovered by me and duly disclosed to Oracle earlier this year. This issue has now been fixed in this Critical Patch Update (and included in Java 1.8.0_65), and so I am free to describe it.

1) Background

I first noticed this issue in the context of signature validation of SOAP web service requests. A signed SOAP request involves using XML Signature to sign some part of the request, where the resulting Signature structure is inserted into the security header of the request. The Signature contains a KeyInfo Element, which references the (public) key to use to validate the request. The recipient must resolve the appropriate public key, establish trust in it, and use it to validate the signature.

A common use-case is when the certificate used to validate the signature is included directly in the request, by BASE-64 encoding it in the security header. Optionally, the full certificate chain can be included instead. The recipient must take the certificates and establish a trust chain using a CA certificate stored in a local truststore, which is then validated.

However, what if the signing certificate has been revoked by the issuing CA? In this case, we can specify a Certificate Revocation List, and include it as part of the validation of the trust chain.

2) The vulnerability

Now to the vulnerability. Under the more usual use-case of just including the signing certificate in the security header, and establishing a trust-chain using a local truststore and CRL file, everything was working fine. Namely, if the signing certificate was trusted, but revoked, then the CertPath validation failed. However, if the issuing certificate of the signing certificate was also included in the security header, then CRL validation was not failing! This vulnerability exists in a range of JDK 8 versions prior to 1.8.0_65. It does not exist prior to JDK 8.

To see how this works using the Java CertPathValidator API, I created a simple maven-based unit test in github:
  • java.crls - A testcase that show how to include a CRL when validating the certificate path of a certificate.
The test has a JUnit failure assertion that asserts that the CertPathValidator validation should fail (as the signing certificate has been revoked). However, this failure assertion is not met when run locally with Java 1.8.0_51. With a Java version post-1.8.0_65 the failure assertion is met, and the test passes.