Jar's CodeSigner null on Java 10, non-null on Java 8
Scott Palmer
swpalmer at gmail.com
Sat Oct 6 20:09:39 UTC 2018
I made a simple test case that will either pass of fail depending on how I choose to launch with Java 10.
On the class path it works.
On the module path AND the class path it works
On the module path executed with -m it fails.
On the module path with another *specific but totally unrelated jar* AND the class path, run using fully-qualified class name it fails.
On the module path only with fully qualified class name the class can’t be found (this is inconsistent with the previous).
# Run with Java 10.0.2
#DEBUG_OPT=-Djava.security.debug=all
#DEBUG_OPT=-Djava.security.debug=jar
# This works:
java --class-path SignTest.jar $DEBUG_OPT example.SignTest
# This works:
java --module-path SignTest.jar --class-path SignTest.jar $DEBUG_OPT example.SignTest
# This fails:
java --module-path SignTest.jar $DEBUG_OPT -m SignTest
# This fails:
java --module-path woodstox-core-asl-4.4.1.jar:SignTest.jar $DEBUG_OPT example.SignTest
# This can't find example.SignTest (Why not, given it can for the above?)
java --module-path SignTest.jar $DEBUG_OPT example.SignTest
# This fails:
java --module-path woodstox-core-asl-4.4.1.jar:SignTest.jar --class-path SignTest.jar $DEBUG_OPT example.SignTest
(Note that no classes from woodstox-core-asl-4.4.1.jar are needed, but its presence changes the behaviour.)
Here is the code. It is the only class in SignTest.jar and that jar is signed with a newly created keypair using the default algorithm, no timestamps
package example;
import java.security.CodeSigner;
import java.security.CodeSource;
import java.security.ProtectionDomain;
public class SignTest {
public static void main(String[] args) {
if (signedByUs(SignTest.class)) {
System.out.println("PASS");
} else {
System.out.println("FAIL");
}
}
private static boolean signedByUs(Class<?> c) {
ProtectionDomain protectionDomain = c.getProtectionDomain();
if (protectionDomain == null) {
return false;
}
CodeSource codeSource = protectionDomain.getCodeSource();
if (codeSource == null) {
return false;
}
CodeSigner[] codeSigners = codeSource.getCodeSigners();
if (codeSigners != null) {
System.out.println(c.getName() + " is signed by something.");
return true;
} else {
System.out.println(c.getName() + " appears to be unsigned.");
return false;
}
}
}
It doesn’t make sense to me, but I am still getting used to modules, so perhaps I am missing something related to modules and security?
Gradle code to build and sign:
apply plugin: 'java'
sourceCompatibility = '1.8'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
if (!hasProperty('mainClass')) {
ext.mainClass = 'example.SignTest'
}
task makeCert() {
if (! new File("$projectDir/testKeystore").exists()) {
println "Creating new test keystore..."
project.exec {
commandLine 'keytool',
'-genkeypair',
'-noprompt',
'-keystore', "$projectDir/testKeystore",
'-keypass', 'testing',
'-storepass', 'testing',
'-dname', 'CN=Test, OU=Test, O=Test, L=Test, ST=Test, C=CA',
'-alias', 'test_alias'
}
} else {
println "Using existing keystore: 'testKeystore"
}
}
jar.dependsOn makeCert
jar {
manifest {
attributes(
'Main-Class' : mainClass
)
}
doLast {
println "Signing jar..."
project.exec {
commandLine = ['jarsigner',
'-keystore', "$projectDir/testKeystore",
'-storepass', 'testing',
'-keypass', 'testing',
jar.archivePath,
'test_alias'
]
}
}
}
Regards,
Scott
> On Oct 6, 2018, at 1:21 AM, Scott Palmer <swpalmer at gmail.com> wrote:
>
> As is too often the case I discovered the difference while trying to isolate a test case. With Java 10 I had extra JVM args to deal with module path and that appeared to cause the problem. I’m not 100% sure what’s happening in my app, but the test case is working so there likely isn’t any issue to bother you guys about. Sorry.
>
> Scott
>
> On Oct 6, 2018, at 12:24 AM, Scott Palmer <swpalmer at gmail.com <mailto:swpalmer at gmail.com>> wrote:
>
>> Sean asked:
>>> On what version of Java 8 does it work?
>>>
>>
>> Up to 8u181 at least.
>>> I am not sure what the problem is without additional information.
>>>
>>> What do you need? I will try to sign something trivial with the same cert and create a test case for a bug report.
>>>
>>> Also, have you tried running with -Djava.security.debug=all? Did
>>> anything unusual (exceptions, etc) get logged?
>> No. All I notice is that on Java 10.0.2 it shows this (names sanitized for public consumption):
>> scl: getPermissions ProtectionDomain (file:/full/path/to/my/signed.jar <no signer certificates>)
>> jdk.internal.loader.ClassLoaders$AppClassLoader at 57536d79
>> <no principals>
>> java.security.Permissions at ba2f4ec (
>> ("java.io.FilePermission” "/full/path/to/my/signed.jar" "read")
>> ("java.lang.RuntimePermission" "exitVM")
>> )
>>
>> and on Java 8u181 it shows this:
>> scl: getPermissions ProtectionDomain (file:/full/path/to/my/signed.jar (Signer: [
>> [
>> Version: V3
>> Subject: CN=My Company Corp., OU=Development, O=My Company Corp., L=Markham, ST=Ontario, C=CA
>> Signature Algorithm: SHA1withDSA, OID = 1.2.840.10040.4.3
>>
>> Key: Sun DSA Public Key
>> Parameters:DSA
>> p: fd7f5381 1d751229 52df4a9c 2eece4e7 f611b752 3cef4400 c31e3f80 b6512669
>> 455d4022 51fb593d 8d58fabf c5f5ba30 f6cb9b55 6cd7813b 801d346f f26660b7
>> 6b9950a5 a49f9fe8 047b1022 c24fbba9 d7feb7c6 1bf83b57 e7c6a8a6 150f04fb
>> 83f6d3c5 1ec30235 54135a16 9132f675 f3ae2b61 d72aeff2 2203199d d14801c7
>> q: 9760508f 15230bcc b292b982 a2eb840b f0581cf5
>> g: f7e1a085 d69b3dde cbbcab5c 36b857b9 7994afbb fa3aea82 f9574c0b 3d078267
>> 5159578e bad4594f e6710710 8180b449 167123e8 4c281613 b7cf0932 8cc8a6e1
>> 3c167a8b 547c8d28 e0a3ae1e 2bb3a675 916ea37f 0bfa2135 62f1fb62 7a01243b
>> cca4f1be a8519089 a883dfe1 5ae59f06 928b665e 807b5525 64014c3b fecf492a
>>
>> y:
>> 4d96a9d5 2b20f1f7 f12decd1 4b5ba0e8 4a98d40a 7d745661 b12f661f 84eae997
>> 071d3619 308961f8 6879f76a 0feba11f e08a63fe b044441a fbd33b3c 30ba3e96
>> e1ac938b bb19ec59 89422123 6b15ad53 ed33e791 a616a61e c6fda1d5 bf95657e
>> 399bb7a1 2ae77ce1 d1806666 5d68c61a 80f967db 525e36c5 a011594a 382ca7aa
>>
>> Validity: [From: Thu May 31 16:16:20 EDT 2012,
>> To: Wed Aug 29 16:16:20 EDT 2012]
>> Issuer: CN=My Company Corp., OU=Development, O=My Company Corp., L=Markham, ST=Ontario, C=CA
>> SerialNumber: [ 4daa8ba0]
>>
>> Certificate Extensions: 1
>> [1]: ObjectId: 2.5.29.14 Criticality=false
>> SubjectKeyIdentifier [
>> KeyIdentifier [
>> 0000: 89 81 49 B9 64 68 72 52 18 39 CE 77 97 7A E9 C9 ..I.dhrR.9.w.z..
>> 0010: 0C C1 C0 5D ...]
>> ]
>> ]
>>
>> ]
>> Algorithm: [SHA1withDSA]
>> Signature:
>> 0000: 30 2C 02 14 3A FE E1 48 12 0A 02 86 D2 C2 17 56 0,..:..H.......V
>> 0010: 98 88 76 B6 E7 10 C6 0B 02 14 7C 59 CC AF F6 8E ..v........Y....
>> 0020: BF ED 27 59 42 E1 78 6E 5C 5E E6 E4 A7 53 ..'YB.xn\^...S
>>
>> ]))
>> sun.misc.Launcher$AppClassLoader at 3d4eac69
>> <no principals>
>> java.security.Permissions at 5cb0d902 (
>> ("java.io.FilePermission" "/full/path/to/my/signed.jar" "read")
>> ("java.lang.RuntimePermission" "exitVM")
>> )
>>
>>>
>>> I would also suggest filing a bug with a reproducible test case, if
>>> possible: https://bugreport.java.com/bugreport/ <https://bugreport.java.com/bugreport/>
>> I’ll try to put something together.
>> Bernd asked:
>>> What are the Hashes, signatures algorithms and key Sizes? Maybe one of the newer security properties turning those off? Does it have a timestamp?
>>
>> SHA1withDSA 1024 bit. There is no timestamp.
>>
>> I checked the $JAVA_HOME/conf/security/java.security file and the key size and algorithm appear to allowed. But there is a lot in there and I’m not 100% sure - What property are you thinking of? I did comment out two of the restrictions that I thought could be related even though they looked okay (jdk.certpath.disabledAlgorithms and jdk.jar.disabledAlgorithms) and it had no effect
>>
>>
>> *please include me in replies, I’m not subscribed to the list*
>>
>> Regards,
>>
>> Scott
>>
>>
>> Excuse me if this isn’t the right place to ask this.
>>
>>
>> I have the following code to check the signature:
>>
>> private static boolean signedByMe(Class<?> c) {
>> ProtectionDomain protectionDomain = c.getProtectionDomain();
>> if ( codeSource == null ) return false;
>> if (codeSigners != null) {
>> byte[] sigKey = cp.getPublicKey().getEncoded();
>> return true;
>> }
>> }
>> }
>> }
>> return false;
>>
>>
>> On Java 8 this works fine.
>>
>> On Java 10.0.2 codeSigners is null.
>>
>>
>> Is this a bug or a specific change to how the expired certificate is handled?
>>
>> Regards,
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/security-dev/attachments/20181006/f5f2c81b/attachment.htm>
More information about the security-dev
mailing list