2011-04-27

BouncyCastle Caveat

Damn.

Another surprise from BouncyCastle 1.46 release. Guys are constantly moving stuff between BER*, DER* and ASN.1* classes ambitiously trying to sort the things out -- aha, good luck sorting out the ASN.1 stuff, -- happily shooting their own legs and greatly helping users to do the same.

It happened so that one of the libraries I'm using provides an interface to RIPEMD-160. As the algorithm is not supported by standard Java out of the box, this library is based on BouncyCastle API, and for at least 4 years already is working with every BC version starting from 1.31 if I remember correctly. Whatever.

With recent BouncyCastle release (1.46) the code just stopped working, with a strange exception:

Exception in thread "main" java.lang.NoSuchFieldError: ripemd160


whereas in the javadoc it clearly states that the field is present:

static final ASN1ObjectIdentifier ripemd160


Writing some debug code did not help: the same code line copied from the library worked fine in Eclipse, but not if called from the library itself.

Temporary solution was to build the project with previous version of BouncyCastle, 1.45. But still, having that done I continued debugging:

import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;

public class Foo {
public static void main(String args[]) {
System.out.println(TeleTrusTObjectIdentifiers.ripemd160.getId());
}
}


Those two failed with exception:

javac -cp .:bcprov-jdk16-145.jar Foo.java && java -cp .:bcprov-jdk16-146.jar Foo
javac -cp .:bcprov-jdk16-146.jar Foo.java && java -cp .:bcprov-jdk16-145.jar Foo


Those two worked fine and printed the OID:

javac -cp .:bcprov-jdk16-145.jar Foo.java && java -cp .:bcprov-jdk16-145.jar Foo
javac -cp .:bcprov-jdk16-146.jar Foo.java && java -cp .:bcprov-jdk16-146.jar Foo


I gave up and asked our Java engineers for help. And while we were digging into class hierarchy, the answer was found: the field type has just changed. It used to be DERObjectIdentifier in 1.45, and in 1.46 it is ASN1ObjectIdentifier. For those ASN.1 gurus here the reason of that change may be obvious, but holy fuck... Is it so hard to use the @deprecated tag for at least some versions? So that people can switch and change the code? Needless to say, the backwards compatibility is also broken. Well, it is the opposite approach of how things are done in the Java itself (some stuff is deprecated from JDK 1.3 I guess), but isn't there something in between?

Good solution for BouncyCastle would be declaring the TeleTrusTObjectIdentifiers.ripemd160 deprecated and introducing the TeleTrusTObjectIdentifiers.RIPEMD160 field of the new type if that is really needed.

Good solution for client programs would be hard-coding the algorithm object identifiers as Strings instead.

Just to sum up, BouncyCastle guys are doing the awesome job and I really see no alternatives to their API. But there is always something to improve.