Wednesday, October 26, 2011

Jars signed with mutliple code signing certificates?

For anyone that has built and maintained Web Start applications, you have probably been through this issue before.   Your QA group or worse yet, a customer, calls to tell you that they cannot start your application because the download failed because "jar resources in jnlp are not signed by the same certificate".

If want your Web Start application to have full access permissions, then you need to sign all the jars that get downloaded.  This generally presents the opportunity to encounter one of the following errors:
  1. None of the jars are signed.  Most likely a build issue and generally only happens once, (I hope!)
  2. Single jar is not signed.  Again, most likely either a build or process error.
  3. Not all jars signed with the same certificate.
The first two are easy to resolve.  The last is a bit of a pain because Web Start doesn't bother to tell you exactly which jars where signed with different code signing certificates.  Now, it's time to make some educated guesses as to what changed recently and look at the most likely/usual suspects.   Another option is to get the list of download jars from the JNLP document and figure out which certificates(s) each jar has been signed with.

We have been through this at work once or twice and so I finally decided to make it easier for the next time this happens.   The approach I took was to read all the jars in a deployment folder, open them and look for the signature files inside the jar file.   For the results, I created a map keyed by the jar name and the value being a list of the signature file names (*.RSA, where the * represents our code signing certificate alias).  Keeping a list in the map allows for cases where a jar may have multiple signature files, which was encountered when we switched over code signing certificates.  Writing this in Java would be possible, but why write so much code? Why not write a script in Groovy, it would be some much shorter and concise.

Groovy Script
def dir = new File("C:\\MyDeployment\\jboss\\myserver\\deploy\\myserver.ear")
def jars = dir.list( { d, f-> f ==~ /.*.jar/ } as FilenameFilter)
def map = [:]
jars.each() {
   def zipFile = new File(dir, it)) 
   zipFile.entries().each { zipEntry ->
      if ('.RSA')) {
          if (map.containsKey(it)) {
             def list = map[it]
             list <<
          } else {
             map[it] = []
map.each{ println it}

Hope this helps!