9

Has anyone done this before? The only reference I have found on google has been: https://web.archive.org/web/20150423130641/http://www.onjava.com/2001/04/12/signing_jar.html which still uses sun.* classes that will cause issues...

Found this as well, but does not work with java16: https://svn.cs.cf.ac.uk/projects/whip/trunk/whip-core/src/main/java/org/whipplugin/data/bundle/JarSigner15.java

Emmanuel Bourg
  • 9,601
  • 3
  • 48
  • 76
wuntee
  • 12,170
  • 26
  • 77
  • 106
  • 2
    you could just call the jar signer process from within java. best using ProcessBuilder. – clamp Oct 07 '11 at 15:16

5 Answers5

5

To address a sudden change of security restrictions in WebStart applications in Java 7u45 we have created a simple signed jar file generator. It uses Guava 15 and Bouncy Castle bcpkix module. It should run on Java 6 & 7. It is suitable for small files only. Use it for any purpose you want.

mmm444
  • 143
  • 2
  • 7
3

Be aware that the sun.security.tools.JarSigner class was written to be used as a command-line utility and wasn't designed to be called from Java code. As a result, the error handling is pretty abrupt: the code will simply print an error message to standard out and then call System.exit() 1.

This means that if you call the class from within your Java code and an error occurs when you try to sign a jar, the JVM running your code will simply stop. This may be fine depending on your situation, but if your code is long running or acting as a service, it's not so good.

It's therefore better to call the jarsigner tool using the ProcessBuilder as per clamp's comment. You can then call waitFor() on the resulting Process object and check exitValue() to see if the command was successful. getInputStream() will let you read any error messages that were written to standard out if the operation fails.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
alphaloop
  • 1,127
  • 12
  • 22
3

Here is how to do this with JDK 9 and beyond:

import java.io.*;
import java.util.zip.*;
import java.security.*;
import jdk.security.jarsigner.*;

char[] password = ...;
String keyStorePath = ...;
KeyStore ks = KeyStore.getInstance(new File(keyStorePath), password);
KeyStore.ProtectionParameter protParam =
   new KeyStore.PasswordProtection(password);

KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry)
   ks.getEntry("codecheck", protParam);

JarSigner signer = new JarSigner.Builder(pkEntry)
   .build();
String inputFile = ...;
String outputFile = ...;
try (ZipFile in = new ZipFile(inputFile);
      FileOutputStream out = new FileOutputStream(outputFile)) {
   signer.sign(in, out);
}

cayhorstmann
  • 3,192
  • 1
  • 25
  • 17
2

In the tools.jar file is the class sun.security.tools.JarSigner which has a static run(ava.lang.String[] strings) method that takes the same parameters as the jarsigner executable does.

So you can call something like:

sun.security.tools.JarSigner.run(new String[] {
    "-keystore", keystoreFile.getAbsolutePath(),
    "-storepass", keystorePassword,
    outFile.getAbsolutePath(),
    keystoreAlias 
});

You need to make sure tools.jar is in your classpath for compiling and execution.

Nathan Voxland
  • 15,453
  • 2
  • 48
  • 64
0

I'm using the SingJar Ant task (which apparently calls the command line tool underneath). It should be possible to call that programmatically.

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720