Wednesday, October 17, 2012

System Properties and the KeyManager

Setting fields using System.setProperty(...) is nasty as it's a global variable by any other name. But sometimes you have to tolerate it when dealing with other people's libraries.

One such library is Java's security classes where you can define your key store file by setting system property javax.net.ssl.keyStore. But be warned: you can only use it once. After that, it is set for the lifetime of the JVM.

If you take a peek into DefaultSSLContextImpl.getDefaultKeyManager(...), you'll see the static defaultKeyManagers being set (from a KeyManagerFactory initiated with a KeyStore that was loaded from the file in the system property). Subsequent calls to this method get the static reference.

This monkeyed around with our test suite no end as it was not immediately obviously where this was being set.

As it happened, an earlier test set it incorrectly but didn't exercise that path of the code. Later in the suite, we saw NoSuchAlgorithmException being thrown by an unrelated test. This is a misleading error.

"NoSuchAlgorithmExceptions are often cause by other underlying exceptions (file not found, wrong password, wrong keystore type, ...)." - from Bruno on StackOverflow.

And so it proved to be. The path the key store value was pointing to didn't exist.

[Miscellaneous: pictures of the SSL Handshake and the Wikipedia description are worth seeing.]

Server Keys

The KeyStore for a server can have many entries. The JavaDocs say:

Each entry in a keystore is identified by an "alias" string. In the case of private keys and their associated certificate chains, these strings distinguish among the different ways in which the entity may authenticate itself. For example, the entity may authenticate itself using different certificate authorities, or using different public key algorithms.

But which entry is passed back to the client? By stepping through the OpenJDK code, I came to this point:



Thread [main] (Suspended)
SunX509KeyManagerImpl.chooseServerAlias(String, Principal[], Socket) line: 271
ServerHandshaker.setupPrivateKeyAndChain(String) line: 1011
ServerHandshaker.trySetCipherSuite(CipherSuite) line: 879
SSLServerSocketImpl.checkEnabledSuites() line: 313
SSLServerSocketImpl.accept() line: 272
.
.

Where I saw this:


        if ((aliases != null) && (aliases.length > 0)) {
            return aliases[0];
        }


The first alias is given to the client no matter what! And thus the private key on the ServerHandshaker object is set.

So, beware if you have other keys in your KeyStore as you might not be giving your client the right one.


Callooh callay! I have OpenJDK

I'm using OpenJDK because I want access to the JCE code to see why my system is behaving the way it is. Since the official JDK Reference Implementation for Java 7 is entirely OpenJDK [1], this seems reasonable.

Remembering I have OpenJDK on my Fedora VM (albeit 1.6), it was just a matter of downloading the source code like any other package. After doing so, I get this:


[phenry@localhost Code]$ rpm -qa | grep openjdk
java-1.6.0-openjdk-devel-1.6.0.0-65.1.10.8.fc15.i686
java-1.6.0-openjdk-1.6.0.0-65.1.10.8.fc15.i686
java-1.6.0-openjdk-src-1.6.0.0-65.1.10.8.fc15.i686


Hoorah! There it is. But where is the actual source file?


[phenry@localhost Code]$ rpm -ql java-1.6.0-openjdk-src-1.6.0.0-65.1.10.8.fc15.i686
/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/src.zip
/usr/share/doc/java-1.6.0-openjdk-src-1.6.0.0
/usr/share/doc/java-1.6.0-openjdk-src-1.6.0.0/README.src


(Posting this because I keep forgetting all that RPM goodness [2]).

[1] Java Platform, Standard Edition 7 Reference Implementation
[2] A good crib sheet on RPM Commands.