Verify and Sign a Jar programmatically - java

I am new to this topic, therefore I hope I use the right vocabulary.
Is it possible to get the possibility of Jarsigner within Java self?
I need the possibility to do the following things programatically:
verify if a jar is signed with a certain private key from a keystore
if the jar is verified: unsign the jar
sign the jar with another private key from an official certificate authority, which is in the same or in another keystore
In pseudo-code I imagine something like this:
JarVerifier verifier = new JarVerifier(/*all needed parameters like the location of the keystore*/);
verifier.verify(jarFile); //returns a value which indicates the result (an Enum or an integer value)
Signing the jar should work in a similar way:
JarSigner signer = new JarSigner(/*all needed parameters like the location of the keystore, passwords, alias*/);
signer.sign(jarFile);
I know that this is a duplicate of many other questions, but I am not happy with their answers. The solution of these answers is in most cases a self-written class, a modification of a class found from OpenJDK or a hint that the code needs still to be written and how this can be done.
This is not acceptable for me, because they are not maintained (or I have to write and maintain the classes myself), I know nothing about their correctness (especially if I have to write the code myself) and license issues.
What I don't get is that there seems to be no easy solution provided by Oracle, especially as it is such a critical topic, where an error might lead to an insecure system.

I try to answer the question myself.
Verifying
To verify the Jar there seems not be be a good ready-to use solution. Therefore own code needs to be written.
Signing
There is the Ant Task SignJar which is able to sign jars and it is possible to use Ant Tasks inside Java
The class to sign the jars can look like this:
public class JarSigner extends SignJar {
public JarSigner() {
project = new Project();
project.init();
taskType = "signJar";
taskName = "signJar";
target = new Target();
}
public static void signJar(File jarToSign, String alias, String keypass, String keystore, String storepass) {
JarSigner signer = new JarSigner();
signer.setJar(jarToSign);
signer.setAlias(alias);
signer.setKeypass(keypass);
signer.setKeystore(keystore);
signer.setStorepass(storepass);
signer.setSignedjar(jarToSign);
signer.execute();
}
}
unsigning
Did not need it yet.

Related

bouncycastle throws exception when file contains a mix of secret and public keys

I am running this code:
public static void main(String[] args) throws IOException, PGPException {
InputStream privateKeyRings = new FileInputStream("/path/to/file/secring.gpg");
PGPSecretKeyRingCollection pgpSecretKeyRings =
new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(privateKeyRings), new JcaKeyFingerprintCalculator());
}
And I get this error:
Exception in thread "main" org.bouncycastle.openpgp.PGPException: org.bouncycastle.openpgp.PGPPublicKeyRing found where PGPSecretKeyRing expected
at org.bouncycastle.openpgp.PGPSecretKeyRingCollection.<init>(Unknown Source)
at test.main(test.java:36)
Therefor I inspected the file secring.gpg by running
gpg --show-keys --no-default-keyring secring.gpg
Which gives me a list of keys
sec# rsa4096 2013-02-21 [SC]
37B...
uid xyz <xyz#xyz.com>
ssb# rsa4096 2013-02-21 [E]
sec# rsa4096 2013-02-14 [SC]
22C...
uid abc <abc#abc.com>
ssb# rsa4096 2013-02-14 [E]
pub rsa4096 2013-04-19 [SC]
5A1...
uid def <def#def.com>
sub rsa4096 2013-04-19 [E]
So as far as I can tell, the file contains secret keys, except for the last entry which seems to be a public key.
So my guess is that this is causing the error.
What is the best way to avoid the error?
Do I need to remove the public key from the file secring.gpg? If so, what is the command for this?
And is there another way to handle this scenario in the java code?
Yes that class supports only secret key 'rings' (note what Bouncy calls a 'keyring' is what GnuPG just calls a key, and what GnuPg calls a keyring is what Bouncy calls a 'collection').
I think the best way is indeed to fix the file. That file name secring.gpg was used by older versions of GnuPG for a file in OpenPGP format that contained only secret keys, not public, so whoever created that file either did something really weird and wrong or was trying to mislead and harm people. I don't think there ever was a command that could fix a public key in secring because that wasn't supposed to happen in the first place. In any case modern GnuPG no longer uses that file; it now uses a directory containing separate files in a libgcrypt-based format.
What you could do is use GnuPG to --import this file (import can handle both secret and public keys, because interchange can in various cases use either) and then --export-secret-keys the desired ones. If you set env var GNUPGHOME to a new (empty) directory and import to that, you can simply export everything valid from that directory and then delete it.
Alternatively you could write your own class which is like PGPSecretKeyRingCollection but ignores (skips) any PGPPublicKeyRing object(s). If the rest of your code, or any code you call to use this data, only uses the behavior of PGPSecretKeyRingCollection and doesn't depend on internals or exact identity -- which by OO doctrine it shouldn't -- you can just substitute your object. In older Java you can even extends the real class, so that it can be stored in variables etc. declared with the real type, but with recent Java (9 up) I think subclassing across modules is restricted and this may require --add-opens or somesuch -- I haven't looked into that area yet.
More ambitiously, Bouncy is opensource, so you could fork it and make this change, and any others you want. Of course you would need to set up a complete build environment for it, and periodically take at least the upstream changes that either provide new features you need or want or are security fixes -- in practice it's almost certainly easier to take all changes, and if something conflicts cross that bridge when you get to it.

Check if plugin used "compile files" when it should've used "provided"

Little background for context:
The application I support allows third parties to develop plugins that can leverage some of our functionality. We hand them our "externalAPI.jar"; they put it in their project, implement some interfaces, and build their own APK. We find the would-be plugin by asking the package manager for all installed applications and see if each has a "pluginclass.xml" in the assets directory. If it has that XML file, we anticipate its contents being the canonical path of a class that implements our ExternalPluginVX interface, and using a new PathClassLoader(ApplicationInfo.sourceDir, this.getClass().getClassLoader()), we load the class, create a new instance, and start using it.
The problem:
Sometimes third parties will put
compile files ("./libs/externalAPI.jar")
in their gradle files instead of the correct syntax:
provided files ("./libs/externalAPI.jar")
The result of course being things don't work properly. Sometimes they almost work, but then have unpredictability in their behavior - usually involving vicious crashes. Notably, since their APK is well-formed in its own right, and the XML file is there, we'll see the plugin, load the target class successfully, instantiate it successfully, and things go haywire from there when they try and reference back to us.
The question:
Is there a way for my application to check at runtime if the other application compiled our API classes into their APK instead of using provided files like they should have?
A viable solution is to use a DexFile.
Since I already have the ApplicationInfo.sourceDir, I can just construct a DexFile and iterate through its contents.
//this variable's value assigned by iterating through context.getPackageManager().getInstalledApplications(0)
ApplicationInfo pkg;
String interfaceTheyShouldntHave = ExternalPluginVX.class.getCanonicalName(); //"com.project.external.ExternalPluginVX"
DexFile dexFile = new DexFile(pkg.sourceDir);
Enumeration<String> entries = dexFile.entries();
while(entries.hasMoreElements()){
String entry = entries.nextElement();
if(entry.equals(interfaceTheyShouldntHave)){
Toast.makeText(ctxt, "Plugin \"" + pluginName + "\" could not be loaded. Please use 'provided files' instead of 'compile files'", Toast.LENGTH_LONG).show();
return;
}
}

Extract signature from keystore in Android Gradle build

I need an approach for extracting the signature from keystore in build procedure. We already this in Java this way:
PackageInfo packageInfo = Application.getContext().getPackageManager().getPackageInfo(Application.getContext().getPackageName(), PackageManager.GET_SIGNATURES);
for (Signature signature : packageInfo.signatures) {
byte[] ba = signature.toByteArray());
// do actions with signatures here ....
}
But we don't want this to be done in Java anymore. Instead we need same thing to be run in scope of Gradle build and result of actions are to be written to the BuildConfig constants or to some generated class.
So currently my plan is below:
take the signature(the first one) from keystore;
run JavaExec to make my actions with signature and return result. Actions are - getting the SHA of this signature and applying Base64
encoding to the result. Another possible problem which may arise is
that not all tasks are available in android gradle plugin. So it may
be possible that I won't be able to run the JavaExec;
write the result into one of the BuildConfig constants with the trick like this ["buildConfigField "string", "signatureSHA",
result"]. And again, not sure that it will work since I don't have an
idea if the BuildConfig class is generated before or after of any other actions in the build.
How can I retrieve the signature from the keystore in step 1?

Sign applets from code [duplicate]

I am new to this topic, therefore I hope I use the right vocabulary.
Is it possible to get the possibility of Jarsigner within Java self?
I need the possibility to do the following things programatically:
verify if a jar is signed with a certain private key from a keystore
if the jar is verified: unsign the jar
sign the jar with another private key from an official certificate authority, which is in the same or in another keystore
In pseudo-code I imagine something like this:
JarVerifier verifier = new JarVerifier(/*all needed parameters like the location of the keystore*/);
verifier.verify(jarFile); //returns a value which indicates the result (an Enum or an integer value)
Signing the jar should work in a similar way:
JarSigner signer = new JarSigner(/*all needed parameters like the location of the keystore, passwords, alias*/);
signer.sign(jarFile);
I know that this is a duplicate of many other questions, but I am not happy with their answers. The solution of these answers is in most cases a self-written class, a modification of a class found from OpenJDK or a hint that the code needs still to be written and how this can be done.
This is not acceptable for me, because they are not maintained (or I have to write and maintain the classes myself), I know nothing about their correctness (especially if I have to write the code myself) and license issues.
What I don't get is that there seems to be no easy solution provided by Oracle, especially as it is such a critical topic, where an error might lead to an insecure system.
I try to answer the question myself.
Verifying
To verify the Jar there seems not be be a good ready-to use solution. Therefore own code needs to be written.
Signing
There is the Ant Task SignJar which is able to sign jars and it is possible to use Ant Tasks inside Java
The class to sign the jars can look like this:
public class JarSigner extends SignJar {
public JarSigner() {
project = new Project();
project.init();
taskType = "signJar";
taskName = "signJar";
target = new Target();
}
public static void signJar(File jarToSign, String alias, String keypass, String keystore, String storepass) {
JarSigner signer = new JarSigner();
signer.setJar(jarToSign);
signer.setAlias(alias);
signer.setKeypass(keypass);
signer.setKeystore(keystore);
signer.setStorepass(storepass);
signer.setSignedjar(jarToSign);
signer.execute();
}
}
unsigning
Did not need it yet.

How can I verifiy signed JARs with pure Java?

I don't want to use the jarsigner -verify. Is there no JAR util package for my problem?
I just want to verfiy a JAR in pure Java.
The "jarsigner" is just a small wrapper for a java program that verifies the jar. Inside your JDK there is a "tools.jar" (usally "C:\programs\Java\jdk1.6.0_13\lib\tools.jar" or something like this). Inside this library there is a class "JarSigner" that provides the desired ability. Just put the "tools.jar" on your classpath!
Heres an example program to demonstrate the behaviour
import sun.security.tools.JarSigner;
public class TestJarSigner {
public static void main(String[] args) {
JarSigner signer = new JarSigner();
signer.run(new String[] { "-verify", "tools.jar" });
}
}
Output is:
jar is unsigned. (signatures missing or not parsable)
The sources are availible if you need a deeper understanding of the signing process.

Categories

Resources